使用 xml.Name 将 xml 解组为 [] 结构

unmarshal xml to []structs with xml.Name

问题

我需要将 XML 从第 3 方应用程序解组到我的 GO 结构。

我试过的

我创建了结构并且能够从我的代码中生成相同的 XML。 @see TestMetaData_Marshal

有效的 XML

我简化了这个例子的xml:

<Parent>
    <Name>tic.TEST</Name>
    <MetaData>
        <LawFormID Type="129" DefinedSize="3">DOO</LawFormID>
        <FirmUQ Type="129" DefinedSize="15">BARTOG</FirmUQ>
        <FirmDescription Type="200" DefinedSize="100">Bartog d.o.o. Trebnje</FirmDescription>
    </MetaData>
</Parent>

结构

我对应的结构如下。 注意:我为元数据创建了一个结构,但我宁愿不使用它(由于json,yaml)

type Parent struct {
    Name string
    MetaData []Node `xml:"MetaData>any"`
}

type Node struct {
    XMLName     xml.Name // this allows custom node names
    Type        int      `xml:"Type,attr,omitempty"`
    DefinedSize int      `xml:"DefinedSize,attr,omitempty"`
    Text        string   `xml:",chardata"` // required at some places, cannot omit
}

@TestMetadata_Marshal


func TestMetaData_Marshal(t *testing.T) {
    parent := Parent{
        Name: "tic.TEST",
        MetaData: []Node{
            {
                XMLName: xml.Name{
                    Local: "LawFormID",
                },
                Text:        "DOO",
                Type:        129,
                DefinedSize: 3,
            }, {
                XMLName: xml.Name{
                    Local: "FirmUQ",
                },
                Text:        "BARTOG",
                Type:        129,
                DefinedSize: 15,
            }, {
                XMLName: xml.Name{
                    Local: "FirmDescription",
                },
                Text:        "Bartog d.o.o. Trebnje",
                Type:        200,
                DefinedSize: 100,
            },
        }, // \MetaData
    }
    HaveXML := XML(parent)
    fmt.Println(HaveXML)
    if ValidXML != HaveXML {
        t.Error(fmt.Errorf("marshaled XML did not match. Have: %v", HaveXML))
    }
}

解组

这就是麻烦的开始;测试 func 很简单;结果是 MetaData 中没有条目可用。
我尝试了很多不同的 tags,还尝试创建自己的 MetaData struct 包含 Items []Node

func TestUnmarshal() {
    var parent Parent
    err := xml.Unmarshal([]byte(ValidXML), &parent)
    if err != nil {
        fmt.Println(err)
        return
    }
    HaveXML := XML(parent)
    if ValidXML == HaveXML {
        fmt.Println("\tmarshaled XML is Valid")
    } else {
        fmt.Printf("\tmarshaled XML did not match. Have:\n%v\n", HaveXML)
    }
}

开始游戏(将测试变成 'normal' 函数

https://goplay.tools/snippet/kWS29HR7O9t

问题

在go&xml中不能这样做吗? 如果有可能,我做错了什么?

问题是 any 不是标签名,它是一个选项。所以使用的时候要在前面加上逗号,e.g. xml:",any".

我不认为你可以将它与 > 结合起来,所以创建一个单独的 MetaData 结构:

type Parent struct {
    Name     string
    MetaData MetaData `xml:"MetaData"`
}

type MetaData struct {
    Nodes []Node `xml:",any"`
}

通过此重构您的示例工作和输出(在 Go Playground 上尝试):

=== TestMarshal
<Parent>
    <Name>tic.TEST</Name>
    <MetaData>
        <LawFormID Type="129" DefinedSize="3">DOO</LawFormID>
        <FirmUQ Type="129" DefinedSize="15">BARTOG</FirmUQ>
        <FirmDescription Type="200" DefinedSize="100">Bartog d.o.o. Trebnje</FirmDescription>
    </MetaData>
</Parent>
    marshaled XML is Valid
=== TestUnmarshal
    marshaled XML is Valid