在Golang的标准库中,encoding/xml包提供了对XML数据的解析和序列化支持,开发者可以通过定义对应的结构体,配合包内的方法快速完成XML文件或字符串的处理,无需手动编写复杂的字符串解析逻辑。

XML解析基础:结构体标签定义
使用encoding/xml解析XML的核心是定义与XML结构匹配的结构体,通过结构体标签指定节点名称、属性、嵌套关系等信息。常用的结构体标签说明如下:
- xml:"节点名":指定结构体字段对应的XML节点名称
- xml:"节点名,attr":指定结构体字段对应XML节点的属性
- xml:"节点名>子节点名":指定嵌套的子节点路径
- xml:",chardata":指定字段获取节点的文本内容
- xml:",innerxml":指定字段获取节点的原始XML内容
解析简单XML字符串
下面通过一个简单的用户XML示例,演示如何解析XML字符串并提取数据:
package main
import (
"encoding/xml"
"fmt"
)
// 定义User结构体,对应XML的用户节点
type User struct {
XMLName xml.Name `xml:"user"` // 指定根节点名称为user
ID int `xml:"id,attr"` // id是user节点的属性
Name string `xml:"name"` // name是user的子节点
Age int `xml:"age"` // age是user的子节点
Email string `xml:"email>addr"` // email节点的子节点addr
}
func main() {
// 待解析的XML字符串
xmlStr := `<user id="1001"><name>张三</name><age>25</age><email><addr>zhangsan@ipipp.com</addr></email></user>`
var user User
// 解析XML到结构体
err := xml.Unmarshal([]byte(xmlStr), &user)
if err != nil {
fmt.Println("解析XML失败:", err)
return
}
// 输出解析结果
fmt.Printf("用户ID: %dn", user.ID)
fmt.Printf("用户姓名: %sn", user.Name)
fmt.Printf("用户年龄: %dn", user.Age)
fmt.Printf("用户邮箱: %sn", user.Email)
}
运行上述代码会输出解析后的用户信息,说明结构体标签正确匹配了XML的节点和属性。
解析XML文件
如果需要解析本地XML文件,可以使用os包读取文件内容后,再调用xml.Unmarshal方法,示例如下:
package main
import (
"encoding/xml"
"fmt"
"os"
)
type User struct {
XMLName xml.Name `xml:"user"`
ID int `xml:"id,attr"`
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email>addr"`
}
func main() {
// 打开XML文件
file, err := os.Open("user.xml")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
defer file.Close()
// 读取文件内容
data, err := os.ReadFile("user.xml")
if err != nil {
fmt.Println("读取文件失败:", err)
return
}
var user User
// 解析文件内容
err = xml.Unmarshal(data, &user)
if err != nil {
fmt.Println("解析XML失败:", err)
return
}
fmt.Printf("解析文件得到用户姓名: %sn", user.Name)
}
XML序列化:结构体转XML
encoding/xml包不仅支持解析XML,还支持将结构体序列化为XML格式,使用xml.Marshal或xml.MarshalIndent方法即可,后者可以生成带缩进的格式化XML:
package main
import (
"encoding/xml"
"fmt"
)
type User struct {
XMLName xml.Name `xml:"user"`
ID int `xml:"id,attr"`
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email>addr"`
}
func main() {
// 创建结构体实例
user := User{
ID: 1002,
Name: "李四",
Age: 28,
Email: "lisi@ipipp.com",
}
// 序列化为带缩进的XML
xmlData, err := xml.MarshalIndent(user, "", " ")
if err != nil {
fmt.Println("序列化失败:", err)
return
}
// 添加XML头
xmlHeader := []byte(xml.Header)
xmlHeader = append(xmlHeader, xmlData...)
fmt.Println(string(xmlHeader))
}
运行后会输出格式化的XML内容,包含标准的XML声明头。
处理复杂嵌套XML
当XML存在多层嵌套或重复节点时,可以使用切片类型来接收重复的节点,示例如下:
package main
import (
"encoding/xml"
"fmt"
)
// 订单项结构体
type OrderItem struct {
ProductName string `xml:"product_name"`
Price float64 `xml:"price"`
Count int `xml:"count"`
}
// 订单结构体
type Order struct {
XMLName xml.Name `xml:"order"`
OrderID string `xml:"order_id,attr"`
UserName string `xml:"user_name"`
Items []OrderItem `xml:"items>item"` // 重复的子节点用切片接收
}
func main() {
xmlStr := `<order order_id="20240501001">
<user_name>王五</user_name>
<items>
<item>
<product_name>笔记本电脑</product_name>
<price>5999.00</price>
<count>1</count>
</item>
<item>
<product_name>鼠标</product_name>
<price>99.00</price>
<count>2</count>
</item>
</items>
</order>`
var order Order
err := xml.Unmarshal([]byte(xmlStr), &order)
if err != nil {
fmt.Println("解析失败:", err)
return
}
fmt.Printf("订单号: %sn", order.OrderID)
fmt.Printf("下单用户: %sn", order.UserName)
for _, item := range order.Items {
fmt.Printf("商品: %s, 单价: %.2f, 数量: %dn", item.ProductName, item.Price, item.Count)
}
}
上述代码可以正确解析包含多个订单项的嵌套XML,通过切片接收重复的item节点数据。
注意事项
在使用encoding/xml包时,需要注意以下几点:
- 结构体字段必须是公开访问的(首字母大写),否则xml包无法给字段赋值
- 如果XML节点名称包含特殊字符或者和Go关键字冲突,可以通过结构体标签指定映射关系
- 解析时如果XML结构和结构体不匹配,会返回解析错误,需要提前确认XML格式和结构体定义一致
- 序列化时如果需要在节点中添加文本内容,可以使用
xml:",chardata"标签
Golangencoding/xmlXML解析XML序列化修改时间:2026-07-10 01:09:28