Golang在XML结构中指定顶级标签

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

Golang specify top-level tag in xml structure

问题

所以我正在尝试将一些XML解组或解码为类型(我还不完全清楚它们之间的区别),但似乎无法指定最外层的类型(在这种情况下是<people>)。当我尝试指定此标签时,不会出现错误,但编组值不包含我期望的任何内容。如何指定最外层的标签,为什么第二个赋值没有预期的行为?

package main

import "fmt"
import "encoding/xml"
import "log"

var data string = `
<people>
  <person>
    <id>46</id>
    <name>John Smith</name>
  </person>
  <person>
    <id>3007</id>
    <name>Joe Smith</name>
  </person>
</people>
`

type Person struct {
    Id   int    `xml:"id"`
    Name string `xml:"name"`
}

type People struct {
    PersonList []Person `xml:"person"`
}

type Response struct {
    PeopleItem People `xml:"people"`
}

func main() {
    // 解析People
    // 无法指定最外层标签<people></people>
    var people People
    err := xml.Unmarshal([]byte(data), &people)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(people)
    // 输出"{[{46 John Smith} {3007 Joe Smith}]}"
    // 这是合理的

    // 尝试解析整个响应,得到的是一个空切片的结构体的结构体
    var response Response
    err = xml.Unmarshal([]byte(data), &response)
    if err != nil {
        log.Fatal(err)
    }

    // response是一个空数组的结构体的结构体
    // 为什么会这样?
    fmt.Println(response)
    // 为什么会输出"{{[]}}"?
}

以上是你提供的代码的翻译。

英文:

So I am trying to Unmarshal or Decode some xml into a type (I am still not entirely clear on what the difference is), and I don't seem to be able to specify the outermost type (in this case &lt;people&gt;). When I try to specify this tag, instead of getting an error, the Marshalled value does not contain any of the content I am expecting. How do you specify the outermost tag and why doesn't the second assignment have the expected behavior?

package main

import &quot;fmt&quot;
import &quot;encoding/xml&quot;
import &quot;log&quot;

var data string = `
&lt;people&gt;
  &lt;person&gt;
    &lt;id&gt;46&lt;/id&gt;
    &lt;name&gt;John Smith&lt;/name&gt;
  &lt;/person&gt;
  &lt;person&gt;
    &lt;id&gt;3007&lt;/id&gt;
    &lt;name&gt;Joe Smith&lt;/name&gt;
  &lt;/person&gt;
&lt;/people&gt;
`

type Person struct {
	Id int `xml:&quot;id&quot;`
	Name string `xml:&quot;name&quot;`
}

type People struct {
	PersonList []Person `xml:&quot;person&quot;`
}

type Response struct {
    PeopleItem People `xml:&quot;people&quot;`
}

func main() {
    // parsing People
    // cannot specify outermost tag &lt;people&gt;&lt;/people&gt;
	var people People
	err := xml.Unmarshal([]byte(data), &amp;people)

	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(people)
    // prints &quot;{[{46 John Smith} {3007 Joe Smith}]}&quot;
    // which is reasonable

    // attempting to parse entire response, yields struct of struct of empty slice
    var response Response
    err = xml.Unmarshal([]byte(data), &amp;response)
    if err != nil {
        log.Fatal(err)
    }

    // response is struct of struct of empty array
    // why does this happen?
    fmt.Println(response)
    // why does this print &quot;{{[]}}&quot; ?
}

答案1

得分: 2

你可以在不修改传入数据的情况下完成这个操作,你可以使用特殊的XMLName xml.Name字段来设置外部标签,然后使用xml:",chardata"来访问其内容。

以下是一个示例:在Go Playground上试一试

package main

import (
	"encoding/xml"
	"fmt"
)

type simpleInt struct {
	XMLName xml.Name `xml:"integer"`
	Int     int      `xml:",chardata"`
}

type simpleString struct {
	XMLName xml.Name `xml:"stringtag"`
	String  string   `xml:",chardata"`
}

type simpleBoolean struct {
	XMLName xml.Name `xml:"boolean"`
	Boolean bool     `xml:",chardata"`
}

func main() {

	bint := []byte("<integer>1138</integer>")
	bstring := []byte("<stringtag>Caimeo</stringtag>")
	btrue := []byte("<boolean>true</boolean>")
	bfalse := []byte("<boolean>false</boolean>")

	i := simpleInt{}
	xml.Unmarshal(bint, &i)
	fmt.Println(i, i.Int)

	s := simpleString{}
	xml.Unmarshal(bstring, &s)
	fmt.Println(s, s.String)

	m := simpleBoolean{}
	xml.Unmarshal(btrue, &m)
	fmt.Println(m, m.Boolean)

	xml.Unmarshal(bfalse, &m)
	fmt.Println(m, m.Boolean)
}
英文:

You can do this without hacking the incoming data, you use the special XMLName xml.Name field to set the outside tag and then use xml:&quot;,chardata&quot; to access it's contents.

Here is an example: Try it on the go playground

package main

import (
	&quot;encoding/xml&quot;
	&quot;fmt&quot;
)

type simpleInt struct {
	XMLName xml.Name `xml:&quot;integer&quot;`
	Int     int      `xml:&quot;,chardata&quot;`
}

type simpleString struct {
	XMLName xml.Name `xml:&quot;stringtag&quot;`
	String  string   `xml:&quot;,chardata&quot;`
}

type simpleBoolean struct {
	XMLName xml.Name `xml:&quot;boolean&quot;`
	Boolean bool     `xml:&quot;,chardata&quot;`
}

func main() {

	bint := []byte(&quot;&lt;integer&gt;1138&lt;/integer&gt;&quot;)
	bstring := []byte(&quot;&lt;stringtag&gt;Caimeo&lt;/stringtag&gt;&quot;)
	btrue := []byte(&quot;&lt;boolean&gt;true&lt;/boolean&gt;&quot;)
	bfalse := []byte(&quot;&lt;boolean&gt;false&lt;/boolean&gt;&quot;)

	i := simpleInt{}
	xml.Unmarshal(bint, &amp;i)
	fmt.Println(i, i.Int)

	s := simpleString{}
	xml.Unmarshal(bstring, &amp;s)
	fmt.Println(s, s.String)

	m := simpleBoolean{}
	xml.Unmarshal(btrue, &amp;m)
	fmt.Println(m, m.Boolean)

	xml.Unmarshal(bfalse, &amp;m)
	fmt.Println(m, m.Boolean)
}

答案2

得分: 1

这里有一个简单的解决方案:添加一个新的独特的顶级元素:

var response Response
err = xml.Unmarshal([]byte("<foo>"+data+"</foo>"), &response)
英文:

Here's a lazy solution: add a new, unique top level element:

var response Response
err = xml.Unmarshal([]byte(&quot;&lt;foo&gt;&quot;+data+&quot;&lt;/foo&gt;&quot;), &amp;response)

huangapple
  • 本文由 发表于 2015年10月29日 08:05:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/33403746.html
匿名

发表评论

匿名网友

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

确定