使用包含切片的结构体时,XML会出现问题吗?

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

xml mischief when using structs containing slices?

问题

我尝试了以下代码,以便理解为什么在使用golang中的xml时会遇到问题。

据我了解,我应该能够将一个结构体进行编组,然后将结果数据解组回相同类型的结构体中?

我期望的结果是一个包含子结构体切片的父结构体,但实际上子结构体切片是空的?

playground链接

package main

import (
	"encoding/xml"
	"fmt"
)

type Parent struct {
	XMLName  xml.Name `xml:"parent"`
	Children []Child  `xml:"children"`
}

type Child struct {
	XMLName xml.Name `xml:"child"`
	ID      int      `xml:"ID"`
}

func main() {
	children := make([]Child, 3)

	for i := range children {
		children[i] = Child{ID: i}
	}

	p1 := Parent{Children: children}

	data, err := xml.Marshal(p1)

	if err != nil {
		fmt.Printf("Error during marshal: %v\n", err)
	}

	fmt.Printf("Raw XML: %v\n", string(data))

	p2 := Parent{}

	err = xml.Unmarshal(data, &p2)

	if err != nil {
		fmt.Printf("Error during unmarshal: %v\n", err)
	}

	fmt.Printf("Unmarshalled struct: %v\n", p2)
}
英文:

I tried the following code in an effort to understand why I'm having issues with my xml in golang.

As I understand it, I should be able to marshal a struct and then unmarshal the resulting data back into a struct of the same type?

Result I expected is a parent struct containing a slice of childs, instead that children slice is nil?

playground link

package main

import (
    "encoding/xml"
	"fmt"
)

type Parent struct {
	XMLName  xml.Name `xml:"parent"`
	Children []Child  `xml:"children"`
}

type Child struct {
	XMLName xml.Name `xml:"child"`
	ID      int      `xml:"ID"`
}

func main() {
	children := make([]Child, 3)

	for i := range children {
		children[i] = Child{ID: i}
	}

	p1 := Parent{Children: children}

	data, err := xml.Marshal(p1)

	if err != nil {
		fmt.Printf("Error during marshal: %v\n", err)
	}
	
	fmt.Printf("Raw XML: %v\n", string(data))

	p2 := Parent{}

	err = xml.Unmarshal(data, &p2)
	
	if err != nil {
		fmt.Printf("Error during unmarshal: %v\n", err)
	}

	fmt.Printf("Unmarshalled struct: %v\n", p2)
}

答案1

得分: 1

它不完全像这样工作:结构体和XML之间没有特定的双射关系。

例如,你生成了以下XML:

<parent><child><ID>0</ID></child><child><ID>1</ID></child></parent>

这是因为你的Child类型有一个带有XML标签"child"的字段XMLName xml.Name
这就是编组的工作原理。参考自http://tip.golang.org/pkg/encoding/xml/#Marshal

XML元素的名称按照以下优先顺序确定:

  • XMLName字段上的标签(如果数据是结构体)
  • 类型为xml.Name的XMLName字段的值
  • 用于获取数据的结构体字段的标签
  • 用于获取数据的结构体字段的名称
  • 序列化类型的名称

现在看看如果你尝试解组它会发生什么:
你的Parent类型使用"children"标记其字段Children []Child,但是你的XML中根本没有<children>标签,只有<child>

如果你使用

type Parent struct {
    XMLName  xml.Name `xml:"parent"`
    Children []Child  `xml:"child"`  // 使用"child",而不是"children"
}

它会按照你的意图正常工作。

英文:

It doesn't work quite like this: There is no ad hoc bijection between a struct and a XML.

E.g. you generate the following XML

&lt;parent&gt;&lt;child&gt;&lt;ID&gt;0&lt;/ID&gt;&lt;/child&gt;&lt;child&gt;&lt;ID&gt;1&lt;/ID&gt;&lt;/child&gt;&lt;/parent&gt;

because your Child type has a field XMLName xml.Name with a xml tag "child".
That's how Marshaling works. From http://tip.golang.org/pkg/encoding/xml/#Marshal

> The name for the XML elements is taken from, in order of preference:
>
> - the tag on the XMLName field, if the data is a struct
> - the value of the XMLName field of type xml.Name
> - the tag of the struct field used to obtain the data
> - the name of the struct field used to obtain the data
> - the name of the marshalled type

Now take a look what happens if you try to Unmarshal it:
Your Parent type tags its field Children []Child with "children"
but your XML simply has no &lt;children&gt; tag inside, only &lt;child&gt;.

If you use

type Parent struct {
    XMLName  xml.Name `xml:&quot;parent&quot;`
    Children []Child  `xml:&quot;child&quot;`  // &quot;child&quot;, not &quot;children&quot;
}

it works like you intended.

huangapple
  • 本文由 发表于 2014年4月25日 18:59:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/23291161.html
匿名

发表评论

匿名网友

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

确定