Go语言中如何反序列化含两种嵌套内容的XML标签?
解决XML标签混合类型数据的解析问题(根据属性值适配不同字段类型)
问题背景
需要解析一种XML数据,其中<custom-attribute>标签的内容类型由attribute-id属性决定:有的标签直接包含字符数据,有的则包含嵌套的<value>子标签。现有代码只能处理单一类型,需实现根据属性值支持不同字段类型的解析逻辑。
解决方案
通过为CustomAttribute结构体实现xml.Unmarshaler接口,自定义XML解析逻辑,根据attribute-id的值选择解析字符数据还是嵌套的<value>子元素。
修改后的完整代码
package main import ( "encoding/xml" "fmt" ) type CustomAttribute struct { AttributeID string `xml:"attribute-id,attr"` StringValue string // 存储字符数据类型的值 SliceValue []string // 存储嵌套<value>标签的内容 } // 实现xml.Unmarshaler接口,自定义解析逻辑 func (ca *CustomAttribute) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { // 先解析attribute-id属性 for _, attr := range start.Attr { if attr.Name.Local == "attribute-id" { ca.AttributeID = attr.Value break } } // 根据属性值分支处理解析逻辑 switch ca.AttributeID { case "shipmentChangelog": // 解析嵌套的<value>标签集合 var valuesWrapper struct { Values []string `xml:"value"` } if err := d.DecodeElement(&valuesWrapper, &start); err != nil { return err } ca.SliceValue = valuesWrapper.Values default: // 解析直接的字符数据内容 var rawContent string if err := d.DecodeElement(&rawContent, &start); err != nil { return err } ca.StringValue = rawContent } return nil } type Customer struct { CustomAttributes []CustomAttribute `xml:"custom-attribute"` } func main() { xmlData := ` <customer> <custom-attribute attribute-id="shipmentChangelog"> <value>06/16/2023 9:22:49 AM PST Shipment has been cancelled: 60686167</value> <value>06/22/2023 2:19:10 PM PST Product has been removed: {"id":"47606963","pid":"FBS100402080001"}</value> </custom-attribute> <custom-attribute attribute-id="isCustomerImported">false</custom-attribute> <custom-attribute attribute-id="customerName">JohnDoe</custom-attribute> </customer> ` var customer Customer if err := xml.Unmarshal([]byte(xmlData), &customer); err != nil { fmt.Println("Error:", err) return } // 打印解析结果 for _, attr := range customer.CustomAttributes { fmt.Printf("Attribute ID: %s\n", attr.AttributeID) if attr.StringValue != "" { fmt.Printf("String Value: %s\n", attr.StringValue) } if len(attr.SliceValue) > 0 { fmt.Println("Slice Values:") for _, v := range attr.SliceValue { fmt.Printf(" - %s\n", v) } } fmt.Println("---") } }
代码说明
- 结构体扩展:新增
StringValue和SliceValue字段,分别对应两种不同类型的内容存储。 - 自定义解析逻辑:
- 先提取
attribute-id属性值,作为解析分支的判断依据; - 针对
shipmentChangelog类型,解析嵌套的<value>标签到字符串切片;其他类型直接解析字符数据到字符串字段。
- 先提取
- 结果使用:解析完成后,可通过字段是否为空判断当前属性的内容类型,进而正确读取对应数据。
运行输出示例
Attribute ID: shipmentChangelog Slice Values: - 06/16/2023 9:22:49 AM PST Shipment has been cancelled: 60686167 - 06/22/2023 2:19:10 PM PST Product has been removed: {"id":"47606963","pid":"FBS100402080001"} --- Attribute ID: isCustomerImported String Value: false --- Attribute ID: customerName String Value: JohnDoe ---
内容的提问来源于stack exchange,提问作者ATLChris
相关产品推荐
相关产品推荐

