Go encoding/xml
Library
encoding/xml - Go Language Standard XML Encoding/Decoding Package
Overview
encoding/xml is an XML serialization package included in Go's standard library. It provides comprehensive functionality for reading and writing XML data, including flexible mapping using struct tags, namespace support, and streaming processing. Supporting various XML processing patterns such as generating and parsing XML documents, DOM manipulation, and SAX-style streaming processing, it is well-suited for handling XML as a web service format, configuration file format, or data exchange format.
Details
The encoding/xml package provides a complete feature set for handling XML in Go. By tagging struct fields, you can declaratively define mappings between XML elements/attributes and struct fields. This design allows intuitive mapping of even complex XML structures to Go's type system.
The package supports both batch processing via Marshal/Unmarshal functions and streaming processing via Encoder/Decoder. For large XML files, the Decoder's token-based processing enables memory-efficient handling. Additionally, by implementing xml.Marshaler and xml.Unmarshaler interfaces, you can define custom serialization logic.
Important XML specification features such as XML namespaces, CDATA, comments, and processing instructions are also supported. However, advanced features like DTD validation or XSD schema validation are not included, so external libraries are needed for such functionality.
Advantages and Disadvantages
Advantages
- Standard Library: XML processing without external dependencies
- Flexible Mapping: Declarative XML-Go type mapping via struct tags
- Streaming Support: Efficient processing of large XML files
- Namespace Support: Proper handling of XML namespaces
- Customizable: Extension through Marshaler/Unmarshaler interfaces
- Type Safety: Safety through compile-time type checking
Disadvantages
- No Schema Validation: DTD and XSD validation not supported
- No XPath Support: No query functionality via XPath expressions
- No XSLT Support: No XSL transformation capabilities
- Performance: May be slower than specialized XML libraries
- Error Messages: XML parse error messages can be unclear
- Completeness: Some XML specifications (external entities, etc.) unsupported
References
Code Examples
1. Basic XML Encode and Decode
package main
import (
"encoding/xml"
"fmt"
"log"
)
type Person struct {
XMLName xml.Name `xml:"person"`
Name string `xml:"name"`
Age int `xml:"age,attr"`
Email string `xml:"contact>email"`
Phone string `xml:"contact>phone"`
}
func main() {
// Encode
person := Person{
Name: "John Doe",
Age: 30,
Email: "[email protected]",
Phone: "555-1234",
}
xmlData, err := xml.MarshalIndent(person, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println("XML Output:")
fmt.Println(xml.Header + string(xmlData))
// Decode
var decoded Person
err = xml.Unmarshal(xmlData, &decoded)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\nDecoded: %+v\n", decoded)
}
2. Complex Structures and Lists
package main
import (
"encoding/xml"
"fmt"
)
type Library struct {
XMLName xml.Name `xml:"library"`
Name string `xml:"name,attr"`
Books []Book `xml:"books>book"`
}
type Book struct {
ISBN string `xml:"isbn,attr"`
Title string `xml:"title"`
Authors []string `xml:"authors>author"`
Publisher string `xml:"publisher"`
Year int `xml:"year"`
Price float64 `xml:"price"`
Currency string `xml:"price,attr,currency"`
}
func complexStructureExample() {
library := Library{
Name: "Tech Library",
Books: []Book{
{
ISBN: "978-0-123456-78-9",
Title: "Go Programming Language",
Authors: []string{"Alan Donovan", "Brian Kernighan"},
Publisher: "Tech Press",
Year: 2023,
Price: 49.99,
Currency: "USD",
},
{
ISBN: "978-0-987654-32-1",
Title: "Practical XML Processing",
Authors: []string{"Jane Smith"},
Publisher: "Data Publishing",
Year: 2022,
Price: 39.99,
Currency: "USD",
},
},
}
xmlData, _ := xml.MarshalIndent(library, "", " ")
fmt.Println(xml.Header + string(xmlData))
}
3. Namespace Handling
package main
import (
"encoding/xml"
"fmt"
)
type Envelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Body Body `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
}
type Body struct {
GetWeather GetWeatherRequest `xml:"http://weather.example.com GetWeather"`
}
type GetWeatherRequest struct {
City string `xml:"city"`
CountryCode string `xml:"countryCode"`
}
func namespaceExample() {
request := Envelope{
Body: Body{
GetWeather: GetWeatherRequest{
City: "New York",
CountryCode: "US",
},
},
}
xmlData, _ := xml.MarshalIndent(request, "", " ")
fmt.Println(string(xmlData))
}
4. Streaming Processing (Large XML Files)
package main
import (
"encoding/xml"
"fmt"
"io"
"strings"
)
func streamingExample() {
xmlData := `
<products>
<product id="1"><name>Product A</name><price>100</price></product>
<product id="2"><name>Product B</name><price>200</price></product>
<product id="3"><name>Product C</name><price>300</price></product>
</products>`
decoder := xml.NewDecoder(strings.NewReader(xmlData))
var inProduct bool
var currentProduct struct {
ID string
Name string
Price string
}
for {
token, err := decoder.Token()
if err == io.EOF {
break
}
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
switch t := token.(type) {
case xml.StartElement:
if t.Name.Local == "product" {
inProduct = true
for _, attr := range t.Attr {
if attr.Name.Local == "id" {
currentProduct.ID = attr.Value
}
}
} else if inProduct {
var value string
decoder.DecodeElement(&value, &t)
switch t.Name.Local {
case "name":
currentProduct.Name = value
case "price":
currentProduct.Price = value
}
}
case xml.EndElement:
if t.Name.Local == "product" {
fmt.Printf("Product: ID=%s, Name=%s, Price=$%s\n",
currentProduct.ID, currentProduct.Name, currentProduct.Price)
currentProduct = struct{ ID, Name, Price string }{}
inProduct = false
}
}
}
}
5. Custom Marshaling
package main
import (
"encoding/xml"
"fmt"
"time"
)
type DateTime struct {
time.Time
}
// MarshalXML implements xml.Marshaler
func (dt DateTime) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
dateStr := dt.Format("2006-01-02T15:04:05")
return e.EncodeElement(dateStr, start)
}
// UnmarshalXML implements xml.Unmarshaler
func (dt *DateTime) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var dateStr string
if err := d.DecodeElement(&dateStr, &start); err != nil {
return err
}
parsed, err := time.Parse("2006-01-02T15:04:05", dateStr)
if err != nil {
return err
}
dt.Time = parsed
return nil
}
type Event struct {
XMLName xml.Name `xml:"event"`
Name string `xml:"name"`
StartTime DateTime `xml:"startTime"`
EndTime DateTime `xml:"endTime"`
}
func customMarshalingExample() {
event := Event{
Name: "Tech Conference",
StartTime: DateTime{time.Now()},
EndTime: DateTime{time.Now().Add(2 * time.Hour)},
}
xmlData, _ := xml.MarshalIndent(event, "", " ")
fmt.Println(string(xmlData))
// Decode test
var decoded Event
xml.Unmarshal(xmlData, &decoded)
fmt.Printf("Event: %s\nStart: %v\nEnd: %v\n",
decoded.Name,
decoded.StartTime.Format("2006/01/02 15:04"),
decoded.EndTime.Format("2006/01/02 15:04"))
}
6. XML and JSON Conversion
package main
import (
"encoding/json"
"encoding/xml"
"fmt"
)
type Product struct {
XMLName xml.Name `xml:"product" json:"-"`
ID int `xml:"id,attr" json:"id"`
Name string `xml:"name" json:"name"`
Description string `xml:"description" json:"description"`
Price float64 `xml:"price" json:"price"`
InStock bool `xml:"inStock" json:"in_stock"`
}
func xmlJsonConversion() {
// Original data
product := Product{
ID: 123,
Name: "High-Performance Laptop",
Description: "Latest CPU and GPU",
Price: 1299.99,
InStock: true,
}
// Convert to XML
xmlData, _ := xml.MarshalIndent(product, "", " ")
fmt.Println("XML Format:")
fmt.Println(string(xmlData))
// Convert to JSON
jsonData, _ := json.MarshalIndent(product, "", " ")
fmt.Println("\nJSON Format:")
fmt.Println(string(jsonData))
// XML to JSON conversion
var fromXML Product
xml.Unmarshal(xmlData, &fromXML)
jsonFromXML, _ := json.MarshalIndent(fromXML, "", " ")
fmt.Println("\nXML→JSON Conversion:")
fmt.Println(string(jsonFromXML))
}