Введение в обработку XML на языке Go
Язык Go (Golang) предоставляет мощный и элегантный способ работы с XML через стандартный пакет encoding/xml. Этот пакет реализует простой интерфейс для чтения (парсинга) и записи (сериализации) XML-документов, используя аннотации к структурам (struct tags). В отличие от многих других языков, Go не требует создания отдельных DOM- или SAX-парсеров — достаточно описать структуру данных, и пакет сам сопоставит XML-теги с полями.
В этой статье мы подробно разберём основные возможности пакета encoding/xml, начиная с базового парсинга и заканчивая продвинутыми техниками: обработкой атрибутов, пространств имён, потоковым чтением больших файлов и генерацией XML. Также рассмотрим популярные сторонние библиотеки, которые могут быть полезны в специфических сценариях.
Основы: парсинг XML в структуры Go
Самый распространённый способ работы с XML в Go — это десериализация (unmarshal) XML-данных в экземпляры структур. Для этого используется функция xml.Unmarshal(). Ключевая особенность — использование тегов xml:"..." в объявлении полей структуры.
Простой пример: парсинг RSS-ленты
package main
import (
"encoding/xml"
"fmt"
)
// Структура для элемента RSS
type 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("Канал: %s\n", rss.Channel.Title)
fmt.Printf("Описание: %s\n", rss.Channel.Description)
for _, item := range rss.Channel.Items {
fmt.Printf("- %s (%s)\n", item.Title, item.Link)
}
}
В этом примере тег xml:"rss" связывает структуру с корневым элементом, а xml:"channel", xml:"item" — с вложенными. Поле XMLName необязательно, но позволяет получить имя корневого элемента.
Работа с атрибутами XML
Атрибуты XML обрабатываются через специальный синтаксис в теге: xml:"имя_тега,attr". Если атрибут находится прямо в корневом элементе, используется 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\n", p.ID, p.Name, p.Age)
// Вывод: ID: 123, Name: Alice, Age: 30
}
Генерация (сериализация) XML
Для создания XML из структуры используется функция xml.Marshal() или xml.MarshalIndent() для форматированного вывода. Пакет автоматически использует теги структур для генерации правильных имён элементов и атрибутов.
type Book struct {
XMLName xml.Name `xml:"book"`
Title string `xml:"title"`
Author string `xml:"author"`
Year int `xml:"year,attr"`
}
func main() {
book := Book{
Title: "The Go Programming Language",
Author: "Donovan & Kernighan",
Year: 2015,
}
output, _ := xml.MarshalIndent(book, "", " ")
fmt.Println(string(output))
}
Вывод:
<book year="2015">
<title>The Go Programming Language</title>
<author>