英文:
unmarshal xml to []structs with xml.Name
问题
问题
我需要将来自第三方应用程序的XML
解组到我的GO结构中。
我尝试过的方法
我创建了结构体,并且能够从我的代码生成相同的XML
。
请参阅TestMetaData_Marshal
。
ValidXML
我为这个示例简化了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>
结构体
我的相应结构体如下。
注意:我为MetaData创建了一个结构体,尽管我更希望不使用结构体(因为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))
}
}
Unmarshal
这是问题开始的地方;测试func
很简单;结果是MetaData
中没有可用的条目。
我尝试了很多不同的tag
,还尝试创建了一个自己的MetaData
结构体,其中包含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)
}
}
go play(将测试转换为'normal' funcs)
https://goplay.tools/snippet/kWS29HR7O9t
问题
在Go中无法实现这个吗?
如果可以实现,我做错了什么?
英文:
Problem
I need to unmarshal XML
from an 3rd party application to my GO struct.
what i tried
I created structs and am able to generate identical XML
from my code.
@see TestMetaData_Marshal
ValidXML
i simplified the xml for this example:
<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>
Structs
my corresponding structs are the following.
NOTE: i created a struct for MetaData though i would prefer to NOT use one (due 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))
}
}
Unmarshal
this is where the troubles begin; the test func
is trivial; result is that no entries in MetaData
are available.
I tried a lot of different tag
s, also tried creating an own MetaData
struct
containing 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)
}
}
go play (turned tests into 'normal' funcs
https://goplay.tools/snippet/kWS29HR7O9t
Question
Is it not possible to do this in go&xml?
Iff it IS possible, what am i doing wrong?
答案1
得分: 3
问题在于any
不是标签名,而是一个选项。因此,在使用它时,你必须在它前面加上逗号,例如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
英文:
The problem is that any
is not the tag name, it's an option. So when using it, you have to put a comma before it, e.g. xml:",any"
.
I don't think you can combine it with >
, so create a separate MetaData
struct:
type Parent struct {
Name string
MetaData MetaData `xml:"MetaData"`
}
type MetaData struct {
Nodes []Node `xml:",any"`
}
With this refactoring your example works and outputs (try it on the 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论