在实际开发中,处理具有混合子元素的XML文档时,一个常见的坑就是试图用 []Item 这种接口切片直接去 xml.Unmarshal。标准库可没这么智能,它没法在运行时猜出接口到底该实例化成哪个具体类型,结果往往是 Items 字段一片空白,甚至直接 panic。

解决方案其实很有意思——核心思路就是放弃“躺平”式地依赖结构体字段标签来自动解码,转而自己掌控整个解码流程。具体来说,需要为容器结构体(比如 MyDoc)手动实现 xml.Unmarshaler 接口。

func (md *MyDoc) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {  
    md.XMLName = start.Name  
    for {  
        token, err := d.Token()  
        if err != nil {  
            return err  
        }  
        switch t := token.(type) {  
        case xml.StartElement:  
            var item Item  
            switch t.Name.Local {  
            case "foo":  
                item = new(Foo) // 注意:必须传指针,new(Foo) 返回 *Foo  
            case "bar":  
                item = new(Bar)  
            default:  
                // 可选择跳过未知元素,或返回错误  
                continue  
            }  
            if err := d.DecodeElement(item, &t); err != nil {  
                return err  
            }  
            md.Items = append(md.Items, item)  
        case xml.EndElement:  
            if t == start.End() {  
                return nil // 结束当前元素解析  
            }  
        }  
    }  
}

这里面有几个细节必须注意:

通过自定义 UnmarshalXML,类型分发逻辑完全由你掌控,既保留了 encoding/xml 高效解析的能力,又实现了多态结构的安全反序列化。可以说,这是在Go语言静态类型约束下,处理动态XML模式的一种标准实践。

本文转载于:https://www.php.cn/faq/2308001.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。