Go语言 如何在解组XML时保持元素排序

eiee3dmh  于 2023-03-21  发布在  Go
关注(0)|答案(1)|浏览(127)

在XML中,元素的顺序非常重要
我有下面的XML:

<s>
    <a toto="toto"/>
    <b data="data"/>
    <a toto="tata"/>
    <b data="doto"/>
</s>

type S struct {
    As      []A      `xml:"a"`
    Bs      []B      `xml:"b"`
}
xml.Unmarshal(MyXML, &S)

我可以从XML中获取所有数据,A和B都经过排序,但是我没有全局顺序的信息,因为A和B在不同的数组中排序。
有没有办法获得元素的全局顺序?(我无法控制XML数据)

ilmyapht

ilmyapht1#

我认为,在“encoding/xml”上没有这样的东西,因为由内部元素组成的是xml结构中的不同字段:

<a toto="toto"/>
<b data="data"/>

此行为的一个替代方法是在最终结构上实现xml.Unmarshaller接口,并手动解码xml字段,将它们保持为相同类型的数组。
大概是这样的

type Child struct {
    Value   string
    TagName string
    Toto    string
    Data    string
}

type S struct {
    Fields []Child
}

并实现解组拆收器:

func (s *S) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    c := Child{}
    for {
        // Token returns the next XML token in the input stream.
        // At the end of the input stream, Token returns nil, io.EOF.
        t, _ := d.Token()

        switch tt := t.(type) {

        case xml.StartElement:
            c.TagName = tt.Name.Local

            if c.TagName == "a" {
                c.Toto = tt.Attr[0].Value
            }
            if c.TagName == "b" {
                c.Data = tt.Attr[0].Value
            }

        case xml.CharData:
            c.Value = string(tt)

        case xml.EndElement:
            if tt.Name.Local == c.TagName {
                s.Fields = append(s.Fields, c)
                c = Child{}
            }

        case nil:
            return nil
        }
    }
}

运行代码:Playground
这只是一个例子,但我认为这可能是一个天真的选择为您的情况。

相关问题