Introducción al procesamiento de XML en el lenguaje Go
El lenguaje Go (Golang) proporciona una forma potente y elegante de trabajar con XML a través del paquete estándar encoding/xml. Este paquete implementa una interfaz simple para leer (analizar) y escribir (serializar) documentos XML, utilizando anotaciones en las estructuras (struct tags). A diferencia de muchos otros lenguajes, Go no requiere la creación de analizadores DOM o SAX separados: basta con describir la estructura de datos, y el paquete asignará automáticamente las etiquetas XML a los campos.
En este artículo, analizaremos en detalle las principales capacidades del paquete encoding/xml, comenzando con el análisis básico y terminando con técnicas avanzadas: manejo de atributos, espacios de nombres, lectura en flujo de archivos grandes y generación de XML. También veremos bibliotecas de terceros populares que pueden ser útiles en escenarios específicos.
Fundamentos: análisis de XML en estructuras de Go
La forma más común de trabajar con XML en Go es deserializar (unmarshal) datos XML en instancias de estructuras. Para esto se utiliza la función xml.Unmarshal(). La característica clave es el uso de etiquetas xml:"..." en la declaración de los campos de la estructura.
Ejemplo simple: análisis de un feed RSS
package main
import ( "encoding/xml" "fmt")
// Estructura para el elemento RSStype 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("Canal: %s", rss.Channel.Title) fmt.Printf("Descripción: %s", rss.Channel.Description) for _, item := range rss.Channel.Items { fmt.Printf("- %s (%s)", item.Title, item.Link) }}En este ejemplo, la etiqueta xml:"rss" vincula la estructura con el elemento raíz, y xml:"channel", xml:"item" con los elementos anidados. El campo XMLName es opcional, pero permite obtener el nombre del elemento raíz.
Trabajo con atributos XML
Los atributos XML se manejan mediante una sintaxis especial en la etiqueta: xml:"nombre_etiqueta,attr". Si el atributo está directamente en el elemento raíz, se usa xml:",attr".
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) // Salida: ID: 123, Name: Alice, Age: 30}Generación (serialización) de XML
Para crear XML a partir de una estructura se utiliza la función xml.Marshal() o xml.MarshalIndent() para una salida formateada. El paquete utiliza automáticamente las etiquetas de las estructuras para generar los nombres correctos de elementos y atributos.
type Book struct { XMLName xml.Name `xml:"book"` Title string