如何将动态的 XML 数据解组为结构体?

huangapple go评论77阅读模式
英文:

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.

&lt;Ht&gt;
&lt;Criteria&gt;
	&lt;ADNode_1&gt;2&lt;/ADNode_1&gt;
	&lt;CDNode_1&gt;2&lt;/CDNode_1&gt;
	&lt;IFNode_1&gt;0&lt;/IFNode_1&gt;
	&lt;ADNode_2&gt;2&lt;/ADNode_2&gt;
	&lt;CDNode_2&gt;0&lt;/CDNode_2&gt;
	&lt;IFNode_2&gt;0&lt;/IFNode_2&gt;
	&lt;ADNode_3&gt;0&lt;/ADNode_3&gt;
	&lt;CDNode_3&gt;0&lt;/CDNode_3&gt;
	&lt;IFNode_3&gt;0&lt;/IFNode_3&gt;
&lt;/Criteria&gt;
&lt;session id=&quot;1056134770841202228344907&quot;&gt;
	&lt;Htd ID=&quot;21170&quot;&gt;
		&lt;Data_1&gt;
			&lt;Info Count=&quot;2&quot;&gt;&lt;/Info&gt;
			&lt;Data Id=&quot;iV29308/B2/R1&quot;&gt;
				&lt;Type&gt;TR1&lt;/Type&gt;
			&lt;/Data&gt;
			&lt;Data Id=&quot;iV29308/B3/R1&quot;&gt;
				&lt;Type&gt;TR1&lt;/Type&gt;
			&lt;/Data&gt;
			&lt;Data Id=&quot;iV29308/B4/R1&quot;&gt;
				&lt;Type&gt;TR1&lt;/Type&gt;
			&lt;/Data&gt;
			&lt;Data Id=&quot;iV29308/B6/R1&quot;&gt;
				&lt;Type&gt;TR1&lt;/Type&gt;
			&lt;/Data&gt;
		&lt;/Data_1&gt;
		&lt;Data_2&gt;
			&lt;Info Count=&quot;2&quot;&gt;&lt;/Info&gt;
			&lt;Data Id=&quot;iV29308/B2/R1&quot;&gt;
				&lt;Type&gt;TR2&lt;/Type&gt;
			&lt;/Data&gt;
			&lt;Data Id=&quot;iV29308/B3/R1&quot;&gt;
				&lt;Type&gt;TR2&lt;/Type&gt;
			&lt;/Data&gt;
			&lt;Data Id=&quot;iV29308/B4/R1&quot;&gt;
				&lt;Type&gt;TR2&lt;/Type&gt;
			&lt;/Data&gt;
			&lt;Data Id=&quot;iV29308/B6/R1&quot;&gt;
				&lt;Type&gt;TR3&lt;/Type&gt;
			&lt;/Data&gt;
		&lt;/Data_2&gt;
	&lt;/Htd&gt;
&lt;/session&gt;

</Ht>

I can create individual structs for &lt;ADNode_1&gt; ,&lt;ADNode_2&gt; and &lt;ADNode_3&gt; or &lt;Data_1&gt;, &lt;Data_2&gt; but there can be n number of these nodes.
Like below

&lt;ADNode_1&gt;2&lt;/ADNode_1&gt;
&lt;ADNode_2&gt;2&lt;/ADNode_2&gt;
&lt;ADNode_3&gt;2&lt;/ADNode_3&gt;
&lt;ADNode_n&gt;2&lt;/ADNode_n&gt;

OR

&lt;Data_1&gt;&lt;/Data_1&gt;
&lt;Data_2&gt;&lt;/Data_2&gt;
&lt;Data_3&gt;&lt;/Data_3&gt;
&lt;Data_n&gt;&lt;/Data_n&gt;

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:&quot;,chardata&quot;`
		} `xml:&quot;,any&quot;`
	}
	Session struct {
		ID  string `xml:&quot;id,attr&quot;`
		Htd struct {
			ID    string `xml:&quot;ID,attr&quot;`
			DataX []struct {
				XMLName xml.Name
				Info    struct {
					Count int `xml:&quot;Count,attr&quot;`
				}
				DataNodes []struct {
					XMLName xml.Name
					ID      string `xml:&quot;Id,attr&quot;`
					Type    string
				} `xml:&quot;,any&quot;`
			} `xml:&quot;,any&quot;`
		}
	} `xml:&quot;session&quot;`
}

Parsing it and reencoding it will retain all elements:

var ht Ht
if err := xml.Unmarshal([]byte(src), &amp;ht); err != nil {
	panic(err)
}

result, err := xml.MarshalIndent(ht, &quot;&quot;, &quot;  &quot;)
if err != nil {
	panic(err)
}

fmt.Println(string(result))

This will output (try it on the Go Playground):

&lt;Ht&gt;
  &lt;Criteria&gt;
    &lt;ADNode_1&gt;2&lt;/ADNode_1&gt;
    &lt;CDNode_1&gt;2&lt;/CDNode_1&gt;
    &lt;IFNode_1&gt;0&lt;/IFNode_1&gt;
    &lt;ADNode_2&gt;2&lt;/ADNode_2&gt;
    &lt;CDNode_2&gt;0&lt;/CDNode_2&gt;
    &lt;IFNode_2&gt;0&lt;/IFNode_2&gt;
    &lt;ADNode_3&gt;0&lt;/ADNode_3&gt;
    &lt;CDNode_3&gt;0&lt;/CDNode_3&gt;
    &lt;IFNode_3&gt;0&lt;/IFNode_3&gt;
  &lt;/Criteria&gt;
  &lt;session id=&quot;1056134770841202228344907&quot;&gt;
    &lt;Htd ID=&quot;21170&quot;&gt;
      &lt;Data_1&gt;
        &lt;Info Count=&quot;2&quot;&gt;&lt;/Info&gt;
        &lt;Data Id=&quot;iV29308/B2/R1&quot;&gt;
          &lt;Type&gt;TR1&lt;/Type&gt;
        &lt;/Data&gt;
        &lt;Data Id=&quot;iV29308/B3/R1&quot;&gt;
          &lt;Type&gt;TR1&lt;/Type&gt;
        &lt;/Data&gt;
        &lt;Data Id=&quot;iV29308/B4/R1&quot;&gt;
          &lt;Type&gt;TR1&lt;/Type&gt;
        &lt;/Data&gt;
        &lt;Data Id=&quot;iV29308/B6/R1&quot;&gt;
          &lt;Type&gt;TR1&lt;/Type&gt;
        &lt;/Data&gt;
      &lt;/Data_1&gt;
      &lt;Data_2&gt;
        &lt;Info Count=&quot;2&quot;&gt;&lt;/Info&gt;
        &lt;Data Id=&quot;iV29308/B2/R1&quot;&gt;
          &lt;Type&gt;TR2&lt;/Type&gt;
        &lt;/Data&gt;
        &lt;Data Id=&quot;iV29308/B3/R1&quot;&gt;
          &lt;Type&gt;TR2&lt;/Type&gt;
        &lt;/Data&gt;
        &lt;Data Id=&quot;iV29308/B4/R1&quot;&gt;
          &lt;Type&gt;TR2&lt;/Type&gt;
        &lt;/Data&gt;
        &lt;Data Id=&quot;iV29308/B6/R1&quot;&gt;
          &lt;Type&gt;TR3&lt;/Type&gt;
        &lt;/Data&gt;
      &lt;/Data_2&gt;
    &lt;/Htd&gt;
  &lt;/session&gt;
&lt;/Ht&gt;

huangapple
  • 本文由 发表于 2022年5月30日 19:32:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/72433664.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定