英文:
How to unmarshal dynamic XML data to struct?
问题
我有一个XML数据,其中包含一些重复的数据,动态元素名称如下所示。
<Ht>
<Criteria>
<ADNode_1>2</ADNode_1>
<CDNode_1>2</CDNode_1>
<IFNode_1>0</IFNode_1>
<ADNode_2>2</ADNode_2>
<CDNode_2>0</CDNode_2>
<IFNode_2>0</IFNode_2>
<ADNode_3>0</ADNode_3>
<CDNode_3>0</CDNode_3>
<IFNode_3>0</IFNode_3>
</Criteria>
<session id="1056134770841202228344907">
<Htd ID="21170">
<Data_1>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR1</Type>
</Data>
</Data_1>
<Data_2>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR3</Type>
</Data>
</Data_2>
</Htd>
</session>
</Ht>
我可以为<ADNode_1>
、<ADNode_2>
和<ADNode_3>
或<Data_1>
、<Data_2>
创建单独的结构体,但这些节点可以有任意数量。
例如:
<ADNode_1>2</ADNode_1>
<ADNode_2>2</ADNode_2>
<ADNode_3>2</ADNode_3>
<ADNode_n>2</ADNode_n>
或者
<Data_1></Data_1>
<Data_2></Data_2>
<Data_3></Data_3>
<Data_n></Data_n>
我该如何创建这些节点的结构体,以便具有任意数量的节点或元素?
这是我正在尝试使用的Playground链接:链接
英文:
I have a XML data which has some repeated data with dynamic element name as shown below.
<Ht>
<Criteria>
<ADNode_1>2</ADNode_1>
<CDNode_1>2</CDNode_1>
<IFNode_1>0</IFNode_1>
<ADNode_2>2</ADNode_2>
<CDNode_2>0</CDNode_2>
<IFNode_2>0</IFNode_2>
<ADNode_3>0</ADNode_3>
<CDNode_3>0</CDNode_3>
<IFNode_3>0</IFNode_3>
</Criteria>
<session id="1056134770841202228344907">
<Htd ID="21170">
<Data_1>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR1</Type>
</Data>
</Data_1>
<Data_2>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR3</Type>
</Data>
</Data_2>
</Htd>
</session>
</Ht>
I can create individual structs for <ADNode_1>
,<ADNode_2>
and <ADNode_3>
or <Data_1>
, <Data_2>
but there can be n number of these nodes.
Like below
<ADNode_1>2</ADNode_1>
<ADNode_2>2</ADNode_2>
<ADNode_3>2</ADNode_3>
<ADNode_n>2</ADNode_n>
OR
<Data_1></Data_1>
<Data_2></Data_2>
<Data_3></Data_3>
<Data_n></Data_n>
How can I create struct for these nodes to have n number of nodes or elements?
Here is the playground link I am trying to work with.
答案1
得分: 1
通常情况下,你可以在Go语言中使用切片(slice)来"收集"元素,并使用,any
选项将没有映射的所有元素放入其中。为了能够识别源,可以使用一个XMLName xml.Name
字段,它将保留它所属的XML标签的名称。
例如,你可以像这样建模你的XML:
type Ht struct {
Criteria struct {
Nodes []struct {
XMLName xml.Name
Content string `xml:",chardata"`
} `xml:",any"`
}
Session struct {
ID string `xml:"id,attr"`
Htd struct {
ID string `xml:"ID,attr"`
DataX []struct {
XMLName xml.Name
Info struct {
Count int `xml:"Count,attr"`
}
DataNodes []struct {
XMLName xml.Name
ID string `xml:"Id,attr"`
Type string
} `xml:",any"`
} `xml:",any"`
}
} `xml:"session"`
}
解析和重新编码将保留所有元素:
var ht Ht
if err := xml.Unmarshal([]byte(src), &ht); err != nil {
panic(err)
}
result, err := xml.MarshalIndent(ht, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(result))
这将输出以下结果(在Go Playground上尝试):
<Ht>
<Criteria>
<ADNode_1>2</ADNode_1>
<CDNode_1>2</CDNode_1>
<IFNode_1>0</IFNode_1>
<ADNode_2>2</ADNode_2>
<CDNode_2>0</CDNode_2>
<IFNode_2>0</IFNode_2>
<ADNode_3>0</ADNode_3>
<CDNode_3>0</CDNode_3>
<IFNode_3>0</IFNode_3>
</Criteria>
<session id="1056134770841202228344907">
<Htd ID="21170">
<Data_1>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR1</Type>
</Data>
</Data_1>
<Data_2>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR3</Type>
</Data>
</Data_2>
</Htd>
</session>
</Ht>
英文:
Generally for these situations you may use a slice in Go to "gather" the elements, and use the ,any
option to put everything in it you don't have a mapping for. To be able to identify the source, use an XMLName xml.Name
field which will retain the name of the XML tag it originates from.
For example you may model your XML like this:
type Ht struct {
Criteria struct {
Nodes []struct {
XMLName xml.Name
Content string `xml:",chardata"`
} `xml:",any"`
}
Session struct {
ID string `xml:"id,attr"`
Htd struct {
ID string `xml:"ID,attr"`
DataX []struct {
XMLName xml.Name
Info struct {
Count int `xml:"Count,attr"`
}
DataNodes []struct {
XMLName xml.Name
ID string `xml:"Id,attr"`
Type string
} `xml:",any"`
} `xml:",any"`
}
} `xml:"session"`
}
Parsing it and reencoding it will retain all elements:
var ht Ht
if err := xml.Unmarshal([]byte(src), &ht); err != nil {
panic(err)
}
result, err := xml.MarshalIndent(ht, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(result))
This will output (try it on the Go Playground):
<Ht>
<Criteria>
<ADNode_1>2</ADNode_1>
<CDNode_1>2</CDNode_1>
<IFNode_1>0</IFNode_1>
<ADNode_2>2</ADNode_2>
<CDNode_2>0</CDNode_2>
<IFNode_2>0</IFNode_2>
<ADNode_3>0</ADNode_3>
<CDNode_3>0</CDNode_3>
<IFNode_3>0</IFNode_3>
</Criteria>
<session id="1056134770841202228344907">
<Htd ID="21170">
<Data_1>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR1</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR1</Type>
</Data>
</Data_1>
<Data_2>
<Info Count="2"></Info>
<Data Id="iV29308/B2/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B3/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B4/R1">
<Type>TR2</Type>
</Data>
<Data Id="iV29308/B6/R1">
<Type>TR3</Type>
</Data>
</Data_2>
</Htd>
</session>
</Ht>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论