Go语言反序列化带编号XML标签问题求助
解决Go XML反序列化问题:提取Setting名称与Register值
原代码核心问题
- 反序列化目标错误:XML根节点是单个
<Settings>,但你用了[]SettingContainer切片接收,导致无法正确解析内部节点。 - 缺少节点过滤逻辑:现有结构体仅接收所有节点,无法精准筛选出
SettingN_register类型的节点。
方案一:调整结构体+解析后过滤
这种方式实现简单,先完整解析XML,再提取所需字段:
package main import ( "bytes" "encoding/xml" "fmt" "strings" ) type SettingContainer struct { XMLName xml.Name `xml:"Settings"` Settings []Setting `xml:",any"` } type Setting struct { XMLName xml.Name `xml:",any"` // 接收SettingN下的所有子节点 Children []SettingRegister `xml:",any"` } type SettingRegister struct { XMLName xml.Name `xml:",any"` Value string `xml:"value,attr"` } func main() { var xmlData = bytes.NewBufferString(` <Settings> <Setting0> <Setting0_register value="0x20" /> <Setting0ArbitraryName value="0x0" /> </Setting0> <Setting1> <Setting1_register value="0x60" /> <Setting1WhateverEnable value="0x0" /> </Setting1> <Setting2> <Setting2_register value="0x80" /> <Setting2blahblah value="0x1" /> </Setting2> <Setting4> <Setting4_register value="0x2fffff8" /> <Setting4ThisCanBeAnything value="0x0" /> </Setting4> </Settings>`) var s SettingContainer if err := xml.Unmarshal(xmlData.Bytes(), &s); err != nil { fmt.Printf("解析错误:%v\n", err) return } // 遍历提取所需数据 for _, setting := range s.Settings { settingName := setting.XMLName.Local for _, child := range setting.Children { if strings.HasSuffix(child.XMLName.Local, "_register") { fmt.Printf("Setting名称:%s,Register值:%s\n", settingName, child.Value) break // 每个Setting下仅一个_register节点,找到即退出循环 } } } }
方案二:自定义UnmarshalXML方法(高效过滤)
直接在反序列化阶段筛选目标节点,减少后续处理开销:
package main import ( "bytes" "encoding/xml" "fmt" "io" "strings" ) type SettingData struct { SettingName string RegisterVal string } type Settings struct { XMLName xml.Name `xml:"Settings"` Items []SettingData `xml:",any"` } // 自定义SettingData的反序列化方法,直接提取所需字段 func (sd *SettingData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { sd.SettingName = start.Name.Local // 遍历SettingN下的所有子节点 for { var elem xml.StartElement err := d.Decode(&elem) if err != nil { if err == io.EOF { break } return err } // 只处理_register结尾的节点 if strings.HasSuffix(elem.Name.Local, "_register") { // 提取value属性 for _, attr := range elem.Attr { if attr.Name.Local == "value" { sd.RegisterVal = attr.Value break } } // 跳过当前节点的结束标签 if err := d.Skip(); err != nil { return err } } else { // 跳过非目标节点 if err := d.Skip(); err != nil { return err } } } return nil } func main() { var xmlData = bytes.NewBufferString(` <Settings> <Setting0> <Setting0_register value="0x20" /> <Setting0ArbitraryName value="0x0" /> </Setting0> <Setting1> <Setting1_register value="0x60" /> <Setting1WhateverEnable value="0x0" /> </Setting1> <Setting2> <Setting2_register value="0x80" /> <Setting2blahblah value="0x1" /> </Setting2> <Setting4> <Setting4_register value="0x2fffff8" /> <Setting4ThisCanBeAnything value="0x0" /> </Setting4> </Settings>`) var s Settings if err := xml.Unmarshal(xmlData.Bytes(), &s); err != nil { fmt.Printf("解析错误:%v\n", err) return } for _, item := range s.Items { fmt.Printf("Setting名称:%s,Register值:%s\n", item.SettingName, item.RegisterVal) } }
内容的提问来源于stack exchange,提问作者Arrrow
相关产品推荐
相关产品推荐

