XML (Extensible Markup Language) is a markup language for encoding documents in a format that is both human-readable and machine-readable. Go's encoding/xml package provides built-in support for encoding Go data structures to XML and decoding XML into Go structures using struct tags similar to JSON.
💡 Key Points
- Use struct tags to control XML element names and attributes
- XMLName field controls the root element name
- Use
xml.Marshal() to encode and xml.Unmarshal() to decode - The
attr tag marks a field as an XML attribute - The
chardata tag marks character data content - Use
xml.Encoder and xml.Decoder for streaming - Support for namespaces, CDATA, comments, and processing instructions
Encoding to XML
Convert Go data structures to XML using xml.Marshal:
package main
import (
"encoding/xml"
"fmt"
)
type Person struct {
XMLName xml.Name `xml:"person"`
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email"`
}
func main() {
p := Person{
Name: "Alice",
Age: 30,
Email: "alice@example.com",
}
xmlData, err := xml.MarshalIndent(p, "", " ")
if err != nil {
fmt.Println("error:", err)
return
}
fmt. Println(xml.Header + string(xmlData))
}
Output:<?xml version="1.0" encoding="UTF-8"?>
<person>
<name>Alice</name>
<age>30</age>
<email>alice@example.com</email>
</person>
Decoding from XML
Parse XML into Go structures using xml.Unmarshal:
package main
import (
"encoding/xml"
"fmt"
)
type Person struct {
XMLName xml.Name `xml:"person"`
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email"`
}
func main() {
xmlStr := `
Bob
25
bob@example.com
`
var p Person
err := xml.Unmarshal([]byte(xmlStr), &p)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Printf("Name: %s, Age: %d, Email: %s\n", p.Name, p. Age, p.Email)
}
Output:Name: Bob, Age: 25, Email: bob@example.com
XML Attributes and Nested Elements
XML supports attributes and nested structures:
package main
import (
"encoding/xml"
"fmt"
)
type Address struct {
City string `xml:"city"`
Country string `xml:"country"`
}
type Person struct {
XMLName xml.Name `xml:"person"`
ID int `xml:"id,attr"`
Name string `xml:"name"`
Address Address `xml:"address"`
}
func main() {
p := Person{
ID: 123,
Name: "Charlie",
Address: Address{
City: "New York",
Country: "USA",
},
}
xmlData, _ := xml.MarshalIndent(p, "", " ")
fmt.Println(xml. Header + string(xmlData))
}
Output:<?xml version="1.0" encoding="UTF-8"?>
<person id="123">
<name>Charlie</name>
<address>
<city>New York</city>
<country>USA</country>
</address>
</person>
Struct Tag Options
| Tag | Example | Description |
| Element Name | ` + "`xml:\"elementname\"`" + ` | Sets XML element name |
| Attribute | ` + "`xml:\"name,attr\"`" + ` | Field becomes an attribute |
| Character Data | ` + "`xml:\",chardata\"`" + ` | Field contains element content |
| CDATA | ` + "`xml:\",cdata\"`" + ` | Wrap content in CDATA section |
| Inner XML | ` + "`xml:\",innerxml\"`" + ` | Raw XML content |
| Comment | ` + "`xml:\",comment\"`" + ` | XML comment |
| Any Element | ` + "`xml:\",any\"`" + ` | Match any element |
| Omit Empty | ` + "`xml:\"name,omitempty\"`" + ` | Omit if zero value |
| Ignore Field | ` + "`xml:\"-\"`" + ` | Skip field entirely |
XML Encoding Functions
| Function | Signature | Use Case |
| Marshal | Marshal(v interface{}) ([]byte, error) | Encode to compact XML |
| MarshalIndent | MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) | Encode to formatted XML |
| Unmarshal | Unmarshal(data []byte, v interface{}) error | Decode XML into struct |
| NewEncoder | NewEncoder(w io.Writer) *Encoder | Create streaming encoder |
| NewDecoder | NewDecoder(r io.Reader) *Decoder | Create streaming decoder |
Type Mappings
| Go Type | XML Representation | Notes |
| bool | true/false | Boolean values |
| int, int8, int16, int32, int64 | Decimal number | Integer values |
| uint, uint8, uint16, uint32, uint64 | Decimal number | Unsigned integer values |
| float32, float64 | Decimal number | Floating-point values |
| string | Character data | Text content |
| []byte | Base64-encoded | Binary data |
| []T | Multiple elements | Repeated elements |
| struct | Nested elements | Complex structures |
| *T | Element or omitted | Optional elements |
| xml.Name | Element name | Controls root element |
Common XML Patterns
| Pattern | Code | Use Case |
| With XML Header | xml. Header + string(xmlData) | Include <? xml version=1.0?> |
| Stream Encoding | xml.NewEncoder(w).Encode(v) | Write directly to io.Writer |
| Stream Decoding | xml.NewDecoder(r).Decode(&v) | Read from io.Reader |
| Token-Based Parsing | for { token, _ := decoder.Token(); ... } | Low-level XML parsing |
| Custom Marshal | func (t T) MarshalXML(e *Encoder, start StartElement) error | Custom encoding logic |
| Custom Unmarshal | func (t *T) UnmarshalXML(d *Decoder, start StartElement) error | Custom decoding logic |
| Namespace Handling | XMLName xml. Name `xml:\"http://example.com/ns elementname\"` | Work with XML namespaces |
XML Features
| Feature | Example | Description |
| Attributes | ID int `xml:\"id,attr\"` | Add attributes to elements |
| Namespaces | xml.Name{Space: \"http://...\", Local: \"name\"} | XML namespace support |
| CDATA Sections | ` + "`xml:\",cdata\"`" + ` | Preserve special characters |
| Comments | ` + "`xml:\",comment\"`" + ` | XML comments |
| Processing Instructions | xml.ProcInst | Processing directives |
| Character Entities | Automatic escaping | <, >, &, etc. |
| Directives | xml.Directive | DOCTYPE and other directives |