
在 Go 的 encoding/xml 包中,可通过结构体字段定义为切片(如 []Impression)来准确映射 XML 中重复出现的同名节点(如 VAST 规范中的多个 ),从而同时支持无损反序列化(unmarshal)和保序、保结构的序列化(marshal)。
在 go 的 `encoding/xml` 包中,可通过结构体字段定义为切片(如 `[]impression`)来准确映射 xml 中重复出现的同名节点(如 vast 规范中的多个 `
XML 标准允许同一父元素下存在多个同名子元素(如 VAST 2.0/3.0 中的多个
以下是一个完整、可运行的示例,聚焦于解析并重建含多个
package main
import (
"encoding/xml"
"fmt"
)
type Impression struct {
ID string `xml:"id,attr"` // 映射 id 属性
Content string `xml:",chardata"` // 映射文本内容(CDATA 或纯文本)
}
type VAST struct {
XMLName xml.Name `xml:"VAST"`
Impressions []Impression `xml:"Ad>InLine>Impression"` // 使用嵌套路径定位,支持多级查找
}
func main() {
src := `<?xml version="1.0" encoding="UTF-8"?><vast version="2.0"><ad id="812030"><inline><impression id="ft_vast_i"></impression><impression id="3rdparty"></impression><impression id="3rdparty"></impression></inline></ad></vast>`
v := &VAST{}
if err := xml.Unmarshal([]byte(src), v); err != nil {
panic("unmarshal failed: " + err.Error())
}
fmt.Printf("Parsed %d Impression nodes:\n", len(v.Impressions))
for i, imp := range v.Impressions {
fmt.Printf(" [%d] id=%q, content=%q\n", i, imp.ID, imp.Content)
}
// 重新序列化 —— 输出保持原始顺序与嵌套结构
out, err := xml.MarshalIndent(v, "", " ")
if err != nil {
panic("marshal failed: " + err.Error())
}
fmt.Println("\nRe-marshaled XML:")
fmt.Println(string(out))
}
✅ 核心要点说明:
- []Impression 字段是实现多节点映射的唯一推荐方式;不可用单个 Impression 或 *Impression 替代,否则仅捕获首个节点。
- xml:"Ad>InLine>Impression" 使用 > 分隔的路径语法,明确指定从根到目标节点的层级关系,避免歧义(注意:不支持通配符或正则,路径必须精确)。
- xml:",chardata" 正确提取元素内联文本(含 CDATA),无需额外解码;Go 自动处理转义与还原。
- 属性(如 id)通过 xml:"name,attr" 声明,与内容字段互不干扰。
⚠️ 注意事项:
- 若 XML 中存在其他同名但语义不同的
(例如位于 内),需为其定义独立结构体字段及专属路径(如 CreativesImpressions []Impressionxml:"Ad>InLine>Creatives>Impression"`),避免路径冲突。 - 切片顺序严格对应 XML 中节点出现顺序,适用于需保留执行时序的场景(如广告监测 URL 调用链)。
- 空元素(如
)会被正确解析为 ID="3rdparty"、Content="",无需特殊处理。
综上,Go 的 XML 包对重复节点的支持简洁而健壮。合理设计结构体切片字段 + 精确路径标签,即可零成本兼容 VAST、RSS、SOAP 等含大量同名元素的真实世界 XML 格式。











