XML 还没有从工程世界消失
现在很多新接口都用 JSON,但 XML 依然存在于不少地方:老系统接口、支付或银行协议、配置文件、RSS、Sitemap、办公文档格式。Go 标准库提供了 encoding/xml,可以像处理 JSON 一样把 XML 映射到结构体,也可以用流式方式逐个 token 解析。
XML 比 JSON 更啰嗦,也多了属性、命名空间、文本节点、嵌套元素等概念。入门阶段不必一口气掌握所有细节,只要能读懂常见结构、正确写标签、处理错误,就能应付很多对接任务。
这篇文章用一个服务配置和一个订单 XML 做例子,讲解 encoding/xml 的基础用法。
解析简单 XML
XML:
<config>
<name>demo-service</name>
<port>8080</port>
</config>
结构体:
type Config struct {
XMLName xml.Name `xml:"config"`
Name string `xml:"name"`
Port int `xml:"port"`
}
解析:
var cfg Config
if err := xml.Unmarshal(data, &cfg); err != nil {
return err
}
fmt.Println(cfg.Name, cfg.Port)
XMLName 可以帮助确认根元素名称。它不是必须字段,但在配置解析里很有用。
从文件读取:
func LoadConfig(path string) (Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return Config{}, fmt.Errorf("read config: %w", err)
}
var cfg Config
if err := xml.Unmarshal(data, &cfg); err != nil {
return Config{}, fmt.Errorf("parse config: %w", err)
}
return cfg, nil
}
解析成功后仍然要做业务校验:
if cfg.Port <= 0 {
return Config{}, fmt.Errorf("port must be positive")
}
解析属性
XML 属性:
<service name="user-api" enabled="true">
<port>8080</port>
</service>
结构体:
type Service struct {
Name string `xml:"name,attr"`
Enabled bool `xml:"enabled,attr"`
Port int `xml:"port"`
}
,attr 表示字段来自属性,而不是子元素。
解析:
var service Service
if err := xml.Unmarshal(data, &service); err != nil {
return err
}
属性适合短小元信息,复杂内容通常放子元素。对接外部 XML 时,结构由对方决定;自己设计配置时,尽量保持简单。
嵌套元素和切片
订单 XML:
<order id="1001">
<user>xiaolin</user>
<items>
<item sku="book-go">
<name>Go 入门书</name>
<quantity>1</quantity>
</item>
<item sku="sticker">
<name>贴纸</name>
<quantity>3</quantity>
</item>
</items>
</order>
结构体:
type Order struct {
ID int64 `xml:"id,attr"`
User string `xml:"user"`
Items []OrderItem `xml:"items>item"`
}
type OrderItem struct {
SKU string `xml:"sku,attr"`
Name string `xml:"name"`
Quantity int `xml:"quantity"`
}
xml:"items>item" 表示进入 items 子元素,再读取多个 item。
使用:
var order Order
if err := xml.Unmarshal(data, &order); err != nil {
return err
}
for _, item := range order.Items {
fmt.Println(item.SKU, item.Quantity)
}
XML 标签要和结构严格对应。字段解析不出来时,先检查路径、属性标记和大小写。
输出 XML
编码:
order := Order{
ID: 1001,
User: "xiaolin",
Items: []OrderItem{
{SKU: "book-go", Name: "Go 入门书", Quantity: 1},
},
}
data, err := xml.MarshalIndent(order, "", " ")
if err != nil {
return err
}
fmt.Println(xml.Header + string(data))
xml.Header 是:
<?xml version="1.0" encoding="UTF-8"?>
如果要写到响应或文件,可以用 Encoder:
encoder := xml.NewEncoder(w)
encoder.Indent("", " ")
if err := encoder.Encode(order); err != nil {
return err
}
小结
Go 的 encoding/xml 可以通过结构体标签处理 XML 元素、属性和嵌套路径。简单 XML 用 xml.Unmarshal 很方便,大文件或复杂流可以用 xml.Decoder。解析后不要忘记业务校验,尤其是配置文件和外部接口。
XML 虽然不如 JSON 常见,但仍然是工程世界的一部分。掌握标准库基本用法,在遇到老系统、RSS、Sitemap 或企业接口时,就不会手忙脚乱。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。