
go 的 `xml.unmarshal` 要求输入 xml 有且仅有一个根元素;若原始数据是多个并列的 `
在 Go 中处理 VMware vSphere 等系统返回的 XML 数据时,一个常见陷阱是:summary.hardware.otherIdentifyingInfo 字段的值并非标准 XML 文档(即带单一根节点),而是多个同级
✅ 正确解法是使用 xml.Decoder,它支持流式解析,可多次调用 Decode() 方法,每次读取并解析一个独立的 XML 元素:
import (
"bytes"
"encoding/xml"
"io"
)
type HostSystemIdentificationInfo struct { // 注意:此处改为普通 struct,非切片
IdentifierValue string `xml:"identifierValue"`
IdentifierType struct {
Label string `xml:"label"`
Summary string `xml:"summary"`
Key string `xml:"key"`
} `xml:"identifierType"`
}
// 解析多个并列的 HostSystemIdentificationInfo
func parseIdentificationInfos(xmlData string) ([]HostSystemIdentificationInfo, error) {
var results []HostSystemIdentificationInfo
decoder := xml.NewDecoder(bytes.NewBufferString(xmlData))
for {
var item HostSystemIdentificationInfo
err := decoder.Decode(&item)
if err == io.EOF {
break // 所有元素已读完
}
if err != nil {
return nil, fmt.Errorf("failed to decode XML item: %w", err)
}
results = append(results, item)
}
return results, nil
}? 关键要点:
- 不要将类型定义为切片(如 []struct{}):xml.Decode() 期望接收一个可寻址的单个值(如 &item),而非切片地址;切片应由调用方手动 append 维护。
- 字段名需与 XML 标签名严格匹配:原代码中 IdentiferValue 拼写错误(多了一个 e),应为 IdentifierValue;Go 的 XML 反序列化对大小写和拼写敏感,否则字段将为空。
- 无需手动处理 xsi:type 属性:只要结构体字段标签正确,encoding/xml 会自动跳过未知属性,不影响主体解析。
- 错误处理不可省略:decoder.Decode() 在遇到格式错误时会返回具体错误(如标签不闭合、非法字符),应显式检查而非忽略。
在你的 vSphere 客户端逻辑中,只需将原 xml.Unmarshal 替换为上述 parseIdentificationInfos 调用:
if p.Name == "summary.hardware.otherIdentifyingInfo" {
infos, err := parseIdentificationInfos(p.Val.Inner)
if err != nil {
return fmt.Errorf("failed to parse host identification info: %w", err)
}
fmt.Printf("Parsed %d identification entries\n", len(infos))
for _, info := range infos {
fmt.Printf("- Value: %q, Type: %q (Key: %q)\n",
info.IdentifierValue,
info.IdentifierType.Label,
info.IdentifierType.Key)
}
}✅ 总结:当面对“无根多节点 XML 字符串”时,xml.Decoder + 循环 Decode() 是 Go 标准库提供的标准、可靠且内存友好的解决方案。避免强行添加虚拟根节点(如










