如何在 Go 中正确反序列化多个同级 XML 元素(而非单个根节点)
技术百科
聖光之護
发布时间:2026-01-01
浏览: 次 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("f
ailed 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 标准库提供的标准、可靠且内存友好的解决方案。避免强行添加虚拟根节点(如
# ai
# 多个
# 第一个
# 只需
# 文档
# 跳过
# 而非
# app
# 只会
# 要将
# go
# 循环
# 字节
# 标准库
# xml
# 字符串
# bug
# 结构体
# 命名空间
# Struct
# 切片
# 不符合
# append
# vmware
# 应由
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- Python与GPU加速技术_CUDA与Numba
- 如何在Golang中操作嵌套切片指针_Golang
- c++怎么操作redis数据库_c++ hired
- 如何高效获取循环末次生成的 NumPy 数组最后一
- Win11怎么连接蓝牙耳机_Win11蓝牙设备配对
- Win11怎么更改任务栏颜色_Windows11个
- 如何使用Golang匿名函数_快速定义临时函数逻辑
- Win11怎么关闭系统声音_Win11系统提示音静
- Python文件和流处理指南_高效读写大体积数据文
- Win11怎么关闭定位服务 Win11禁止应用获取
- php怎么下载安装并配置环境变量_命令行调用PHP
- Win11开始菜单打不开_修复Windows 11
- 如何使用Golang配置安全开发环境_防止敏感信息
- 如何使用Golang读取日志文件_Golang b
- php接口返回数据乱码怎么办_php接口调试编码问
- PHP主流架构怎么监控运行状态_工具推荐【操作】
- Win11怎么设置单手模式_Win11触控键盘布局
- 如何在Windows中创建新的用户账户?(标准与管
- Win11怎样安装钉钉客户端_Win11安装钉钉教
- 如何使用Golang指针与接口结合_实现方法调用和
- Python脚本参数接收_sys与argparse
- 如何使用Golang table-driven基准
- Win11怎么关闭SmartScreen_禁用Wi
- c++20的std::format怎么用 比pri
- 如何在 Go 应用中实现自动错误恢复与进程重启机制
- Mac怎么设置鼠标滚动速度_Mac鼠标设置详细参数
- 如何在 Pandas 中按元素交集合并两列字符串
- Win11怎么开启窗口对齐助手_Windows11
- Win10怎么设置开机密码_Windows10账户
- Win11怎么设置虚拟桌面 Win11新建多桌面切
- 如何使用正则表达式精确匹配最多含一个换行符的 st
- 如何在Golang中处理数据库事务错误_回滚和日志
- Windows蓝屏错误0x00000018怎么处理
- c++怎么实现高并发下的无锁队列_c++ std:
- C++中的协变与逆变是什么?C++函数指针与返回类
- Avalonia如何实现跨窗口通信 Avaloni
- 如何使用Golang写入二进制文件_Golang
- Mac怎么给文件夹加密_Mac创建加密磁盘映像教程
- php订单日志权限怎么设_php订单日志文件权限设
- PHP的FastAdmin架构适合二次开发吗_特点
- c++协程和线程的区别 c++异步编程模型对比【核
- 如何在Golang中优化文件读写性能_使用缓冲和并
- 如何使用 Selenium 正确获取篮球参考网站球
- c++的mutex和lock_guard如何使用
- Linux如何安装Golang环境_Linux下G
- Windows怎样拦截QQ浏览器广告_Window
- Ajax提交表单PHP怎么接收_处理Ajax发送的
- 如何使用Golang实现路由分组管理_Golang
- Win11如何设置鼠标灵敏度_Win11鼠标灵敏度
- Win11搜索栏无法输入_解决Win11开始菜单搜

ailed 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)
}
}
QQ客服