使用Golang处理带有属性的XML文档。

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

xml document with attributes with golang

问题

我有一个XML文档,看起来像这样:

<?xml version="1.0"?>
<!DOCTYPE venue SYSTEM "z.dtd">
<venue>
<c>
    <a n="k1"><i>0</i></a>
    <a n="k2"><b v="f"/></a>
</c>
</venue>

我想提取k1(整数),0,以及k2(布尔值),false。

如何使用"encoding/xml"来实现这个?

英文:

I have an XML document which looks like this

&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;!DOCTYPE venue SYSTEM &quot;z.dtd&quot;&gt;
&lt;venue&gt;
&lt;c&gt;
    &lt;a n=&quot;k1&quot;&gt;&lt;i&gt;0&lt;/i&gt;&lt;/a&gt;
    &lt;a n=&quot;k2&quot;&gt;&lt;b v=&quot;f&quot;/&gt;&lt;/a&gt;
&lt;/c&gt;
&lt;/venue&gt;

I would like to extract k1 (integer) , 0 and also k2 (bool) , false

How can I do this with "encoding/xml" ?

答案1

得分: 3

你需要使用Go结构体来建模你的XML结构。

对于可能具有不同内容(子元素)的元素,一种选项是列出所有可能的变体,只有遇到的元素才会被解组。

你可以这样建模你的XML结构:

type Venue struct {
    As []A `xml:"c>a"`
}

type A struct {
    N string `xml:"n,attr"`
    I I      `xml:"i"`
    B B      `xml:"b"`
}

type I struct {
    I int `xml:",chardata"`
}

type B struct {
    V bool `xml:"v,attr"`
}

解组XML文档的代码如下:

func main() {
    var v Venue
    err := xml.Unmarshal([]byte(data), &v)
    fmt.Printf("%+v %v", v, err)
}

const data = `<?xml version="1.0"?>
<!DOCTYPE venue SYSTEM "z.dtd">
<venue>
    <c>
        <a n="k1"><i>1</i></a>
        <a n="k2"><b v="f"/></a>
    </c>
</venue>`

输出结果(在Go Playground上尝试):

{As:[{N:k1 I:{I:1} B:{V:false}} {N:k2 I:{I:0} B:{V:false}}]} <nil>

如你所见,Venue.As 切片的第一个元素具有 A.N=k1,并且它具有从XML中获取的 A.I.I=1 值。

Venue.As 切片的第二个元素具有 A.N=k2,并且它具有从XML中获取的 A.B.V=false 值。

如果你对“包装”A结构体同时包含 IB 字段感到困扰(即使只有其中一个包含有效数据),你可以将它们声明为指针,而不在XML中出现的那个将为 nil(这样很明显且容易判断哪个元素在XML中出现):

type A struct {
    N string `xml:"n,attr"`
    I *I     `xml:"i"`
    B *B     `xml:"b"`
}

这次的输出结果(在Go Playground上尝试):

{As:[{N:k1 I:0x1050e24c B:<nil>} {N:k2 I:<nil> B:0x1050e2f5}]} <nil>
英文:

You have to model your XML structure with Go structs.

For elements which may have varying content (child elements), one option is to list all possible variations, and only the encountered element will be unmarshaled.

Your XML structure can be modeled like this:

type Venue struct {
	As []A `xml:&quot;c&gt;a&quot;`
}

type A struct {
	N string `xml:&quot;n,attr&quot;`
	I I      `xml:&quot;i&quot;`
	B B      `xml:&quot;b&quot;`
}

type I struct {
	I int `xml:&quot;,chardata&quot;`
}

type B struct {
	V bool `xml:&quot;v,attr&quot;`
}

And code to unmarshal the XML document:

func main() {
	var v Venue
	err := xml.Unmarshal([]byte(data), &amp;v)
	fmt.Printf(&quot;%+v %v&quot;, v, err)
}

const data = `&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;!DOCTYPE venue SYSTEM &quot;z.dtd&quot;&gt;
&lt;venue&gt;
&lt;c&gt;
    &lt;a n=&quot;k1&quot;&gt;&lt;i&gt;1&lt;/i&gt;&lt;/a&gt;
    &lt;a n=&quot;k2&quot;&gt;&lt;b v=&quot;f&quot;/&gt;&lt;/a&gt;
&lt;/c&gt;
&lt;/venue&gt;`

Output (try it on the Go Playground):

{As:[{N:k1 I:{I:1} B:{V:false}} {N:k2 I:{I:0} B:{V:false}}]} &lt;nil&gt;

As you can see, the first element of the Venue.As slice has A.N=k1, and it has the A.I.I=1 value, which was taken from the XML.

The second element of the Venue.As slice has A.N=k2, and it has the A.B.V=false value, taken from the XML.

If it bothers you that the "wrapper" A struct contains both the I and the B fields (even though only one of them contains valid data), you may declare them to be pointers, and the one that is not present in the XML will be nil (making it obvious and easy to tell which element was present in the XML):

type A struct {
	N string `xml:&quot;n,attr&quot;`
	I *I     `xml:&quot;i&quot;`
	B *B     `xml:&quot;b&quot;`
}

Output this time (try it on the Go Playground):

{As:[{N:k1 I:0x1050e24c B:&lt;nil&gt;} {N:k2 I:&lt;nil&gt; B:0x1050e2f5}]} &lt;nil&gt;

huangapple
  • 本文由 发表于 2016年12月14日 21:38:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/41144058.html
匿名

发表评论

匿名网友

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

确定