Introduction to XML Processing in Go
The Go language (Golang) provides a powerful and elegant way to work with XML through the standard encoding/xml package. This package implements a simple interface for reading (parsing) and writing (serializing) XML documents using struct annotations (struct tags). Unlike many other languages, Go does not require creating separate DOM or SAX parsers — you just need to describe the data structure, and the package will map XML tags to fields automatically.
In this article, we will thoroughly explore the main features of the encoding/xml package, starting from basic parsing and moving to advanced techniques: handling attributes, namespaces, streaming large files, and generating XML. We will also look at popular third-party libraries that can be useful in specific scenarios.
Basics: Parsing XML into Go Structures
The most common way to work with XML in Go is to deserialize (unmarshal) XML data into struct instances. This is done using the xml.Unmarshal() function. The key feature is the use of xml:"..." tags in the struct field declarations.
Simple Example: Parsing an RSS Feed
package main
import ( "encoding/xml" "fmt")
// Structure for an RSS itemtype RSS struct { XMLName xml.Name `xml:"rss"` Channel Channel `xml:"channel"`}
type Channel struct { Title string `xml:"title"` Description string `xml:"description"` Items []Item `xml:"item"`}
type Item struct { Title string `xml:"title"` Link string `xml:"link"` Description string `xml:"description"`}
func main() { data := `<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>Example Feed</title> <description>A sample RSS feed</description> <item> <title>First Post</title> <link>https://example.com/1</link> <description>This is the first post.</description> </item> </channel> </rss>`
var rss RSS err := xml.Unmarshal([]byte(data), &rss) if err != nil { panic(err) }
fmt.Printf("Channel: %s", rss.Channel.Title) fmt.Printf("Description: %s", rss.Channel.Description) for _, item := range rss.Channel.Items { fmt.Printf("- %s (%s)", item.Title, item.Link) }}In this example, the xml:"rss" tag links the structure to the root element, and xml:"channel", xml:"item" link to nested elements. The XMLName field is optional but allows you to get the name of the root element.
Working with XML Attributes
XML attributes are handled using a special syntax in the tag: xml:"tag_name,attr". If the attribute is directly in the root element, xml:",attr" is used.
type Person struct { XMLName xml.Name `xml:"person"` ID int `xml:"id,attr"` Name string `xml:"name"` Age int `xml:"age,attr"`}
func main() { xmlData := `<person id="123" age="30"><name>Alice</name></person>` var p Person xml.Unmarshal([]byte(xmlData), &p) fmt.Printf("ID: %d, Name: %s, Age: %d", p.ID, p.Name, p.Age) // Output: ID: 123, Name: Alice, Age: 30}Generating (Serializing) XML
To create XML from a structure, use the xml.Marshal() function or xml.MarshalIndent() for formatted output. The package automatically uses struct tags to generate correct element names and attributes.
type Book struct { XMLName xml.Name `xml:"book"` Title string