英文:
xml mischief when using structs containing slices?
问题
我尝试了以下代码,以便理解为什么在使用golang中的xml时会遇到问题。
据我了解,我应该能够将一个结构体进行编组,然后将结果数据解组回相同类型的结构体中?
我期望的结果是一个包含子结构体切片的父结构体,但实际上子结构体切片是空的?
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?
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
<parent><child><ID>0</ID></child><child><ID>1</ID></child></parent>
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 <children> tag inside, only <child>.
If you use
type Parent struct {
    XMLName  xml.Name `xml:"parent"`
    Children []Child  `xml:"child"`  // "child", not "children"
}
it works like you intended.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论