怎么用Go语言的encoding/xml包处理XML

Go的encoding/xml包通过结构体标签实现XML与Go类型的双向映射,支持属性、文本、嵌套、切片及忽略字段等特性,用Unmarshal解析、Marshal生成XML。

Go 的 encoding/xml 包是标准库中处理 XML 的核心工具,主打结构化、类型安全、简洁高效。它不提供流式解析(如 SAX)或 DOM 树操作,而是通过 Go 结构体与 XML 元素一一映射,用 xml.Unmarshal 解析,xml.Marshal 生成。

定义结构体并打上 xml 标签

XML 解析的关键是让 Go 结构体“知道”每个字段对应哪个 XML 元素或属性。靠的是结构体字段的 xml 标签:

  • xml:"name":匹配名为 name 的子元素(默认行为)
  • xml:"name,attr":匹配名为 name 的 XML 属性(如 中的 id
  • xml:",chardata":捕获元素的文本内容(如 Hello 中的 Hello
  • xml:",omitempty":序列化时若字段为空(零值),则忽略该元素或属性
  • xml:"-" :完全忽略该字段(不解析也不生成)

示例:

type Person struct {
  XMLName xml.Name `xml:"person"`
  ID int `xml:"id,attr"`
  Name string `xml:"name"`
  Age int `xml:"age"`
  Bio string `xml:"bio,omitempty"`
}

解析 XML 字符串或文件

xml.Unmarshal 将 XML 数据(字节切片或 io.Reader)解码进结构体实例:

  • 从字符串解析:先用 []byte(xmlStr) 转为字节切片
  • 从文件解析:用 os.Open 打开后传入 xml.NewDecoder,更省内存(尤其大文件)
  • 注意错误检查:解析失败通常返回 xml.SyntaxError 或字段类型不匹配等错误

简单例子:

data := `Alice30`
var p Person
err := xml.Unmarshal([]byte(data), &p)
if err != nil {
  log.Fatal(err)
}
// p.ID == 42, p.Name == "Alice", p.Age == 30

生成 XML 输出

xml.Marshal 把结构体转成 XML 字节切片,再用 string() 或写入文件:

  • 输出带缩进?用 xml.MarshalIndent,传入前缀和缩进符(如 "", " "
  • 想加 XML 声明()?需手动拼接,Marshal 不自动生成
  • 字段为 nil 指针或空 slice 时,配合 omitempty 可跳过输出
out, _ := xml.MarshalIndent(p, "", " ")
fmt.Println(xml.Header + string(out))

处理嵌套、切片和任意子元素

结构体可自然表达嵌套关系:

  • 嵌套结构体 → 对应子元素嵌套
  • 字段类型为 []Child → 自动解析多个同名子元素为切片
  • xml:",any" 捕获未知子元素(返回 []byte,需二次解析)
  • xml:",innerxml" 获取某元素内部所有原始 XML(包括子标签和文本)

例如支持多个 Library

type Library struct {
  XMLName xml.Name `xml:"library"`
  Books []Book `xml:"book"`
}
type Book struct {
  Title string `xml:"title"`
  Author string `xml:"author"`
}

基本上就这些。不需要第三方库,标准包已足够应对绝大多数 XML 场景——只要 XML 结构相对固定,且你愿意用结构体建模。