Golang XML解组问题:本地名称冲突失败

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

Golang XML unmarshalling issue: local name collisions fail

问题

我遇到了错误的行为(或者我做错了什么)。
Golang的XML解组似乎无法处理特定情况下的本地名称冲突。
也就是说,当一个元素有两个子元素,它们的本地名称都相同时("book"),一个没有命名空间(默认或空),另一个有显式命名空间。

举个(人为制造的)例子:

<library
   xmlns:lib="http://foobar.com/ns/library">
   <lib:book>
     AAA
   </lib:book>
   <book>
     ZZZ
   </book>
</library>

如果我使用以下结构体来表示:

type Library_Type struct {
   Book string `xml:"book,omitempty" json:",omitempty"`
   Book_lib string `xml:"http://foobar.com/ns/library book,omitempty" json:",omitempty"`
   Lib string `xml:"xmlns lib,attr"`
}

并尝试解组,它根本不起作用:源代码:http://play.golang.org/p/YW2XpTVRs5

输出:

{"Lib":""}
{"Lib":""}

然而,如果我在结构体中注释掉 'Book string':http://play.golang.org/p/BRv6tUNreM

输出:

{"Book_lib":"\n AAA\n ","Lib":"http://foobar.com/ns/library"}

如果我注释掉 'Book_lib'...:http://play.golang.org/p/u_Up9X9YMp

输出:

{"Book":"\n ZZZ\n ","Lib":"http://foobar.com/ns/library"}

如果我在 'Book' 前面加一个空格:
从:

    Book string `xml:"book,omitempty" json:",omitempty"`

变为:

    Book string `xml:" book,omitempty" json:",omitempty"`

然而,如果添加两个空格(可以解释为第一个空格是命名空间,第二个空格是空白分隔;当没有命名空间时,调用xml.StartElement.Name.Space等于""):

变为:

    Book string `xml:"  book,omitempty" json:",omitempty"`

http://play.golang.org/p/Br_WBR3U8K

输出:

{"Book_lib":"\n     AAA\n   ","Lib":"http://foobar.com/ns/library"}

如果我有两个显式命名空间,问题就消失了(输出是预期的输出):http://play.golang.org/p/llpMuC0SV8

输出:

{"Book_bin":"\n ZZZ\n ","Book_lib":"\n AAA\n ","Lib":"http://foobar.com/ns/library","Bin":"http://foobar.com/ns/bin"}

所以,除非我在这里做错了什么,XML中混合了默认(空)命名空间和具有本地名称冲突的显式命名空间的用例似乎无法正常工作,这是一个错误。

但如果你能找到一个解决这个问题的方法,我会很感激。

英文:

I am getting incorrect behaviour (or I am doing something wrong).
The golang XML demarshalling does not appear to handle a specific case of local name collisions.
That is, where you have one element that has 2 child elements, both with the same local name ("book") but one with no namespace (or default or empty), and the other with an explicit namespace.

For (a contrived) example:

&lt;library
   xmlns:lib=&quot;http://foobar.com/ns/library&quot;&gt;
   &lt;lib:book&gt;
     AAA
   &lt;/lib:book&gt;
   &lt;book&gt;
     ZZZ
   &lt;/book&gt;
&lt;library&gt;

If I use the following struct to represent this:

type Library_Type struct {
   Book string `xml:&quot;book,omitempty&quot; json:&quot;,omitempty&quot;`
   Book_lib string `xml:&quot;http://foobar.com/ns/library book,omitempty&quot; json:&quot;,omitempty&quot;`
   Lib string `xml:&quot;xmlns lib,attr&quot;`
}

And try to demarshal, it does not work at all: Source: http://play.golang.org/p/YW2XpTVRs5

Output:

{&quot;Lib&quot;:&quot;&quot;}
{&quot;Lib&quot;:&quot;&quot;}

However, if I comment out the 'Book string' in the struct: http://play.golang.org/p/BRv6tUNreM

Output:

{&quot;Book_lib&quot;:&quot;\n AAA\n &quot;,&quot;Lib&quot;:&quot;http://foobar.com/ns/library&quot;}

If I comment out the 'Book_lib'...: http://play.golang.org/p/u_Up9X9YMp

Output:

{&quot;Book&quot;:&quot;\n ZZZ\n &quot;,&quot;Lib&quot;:&quot;http://foobar.com/ns/library&quot;}

If I add a space in front of 'Book':
From:

    Book string `xml:&quot;book,omitempty&quot; json:&quot;,omitempty&quot;`

To:

    Book string `xml:&quot; book,omitempty&quot; json:&quot;,omitempty&quot;`

However, adding 2 spaces (which could be interpreted as the first space being the namespace, and the second space whitespace separation; when there is no namespace, calling xml.StartElement.Name.Space equals ""):

To:

    Book string `xml:&quot;  book,omitempty&quot; json:&quot;,omitempty&quot;`

http://play.golang.org/p/Br_WBR3U8K

Output:

{&quot;Book_lib&quot;:&quot;\n     AAA\n   &quot;,&quot;Lib&quot;:&quot;http://foobar.com/ns/library&quot;}

If I have two exlicit name spaces, the problem goes away (the output is the expected output): http://play.golang.org/p/llpMuC0SV8

Output:

{&quot;Book_bin&quot;:&quot;\n ZZZ\n &quot;,&quot;Book_lib&quot;:&quot;\n AAA\n &quot;,&quot;Lib&quot;:&quot;http://foobar.com/ns/library&quot;,&quot;Bin&quot;:&quot;http://foobar.com/ns/bin&quot;}

So, unless I am doing something wrong here, the use case where XML has a mix of default (empty) namespace and explicit namespaces with local name collisions appears to not work and this is a bug.

But if you could find me a way around this I would appreciate it.

答案1

得分: 3

这个问题非常有趣,我实际上不得不做一些研究才能理解它。

  1. 你需要为书籍使用一个单独的结构体。

  2. 你需要使用 ,chardata 来表示实际的值。

type Library struct {
	XMLName xml.Name `xml:"library"`
	Entry   []Book   `xml:"book"`
}

type Book struct {
	XMLName xml.Name `xml:"book"`
	Name    string   `xml:",chardata"`
}

你可以在这个 playground 上查看示例代码。

英文:

This question is very interesting, and I actually had to do some research to get it.

  1. You will have to use a separate struct for the books

  2. You will need to use ,chardata for the actual value.

<kbd>playground</kbd>

type Library struct {
	XMLName xml.Name `xml:&quot;library&quot;`
	Entry []Book `xml:&quot;book&quot;`
}

type Book struct {
	XMLName xml.Name `xml:&quot;book&quot;`
	Name   string   `xml:&quot;,chardata&quot;`
}

huangapple
  • 本文由 发表于 2014年7月22日 00:43:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/24870309.html
匿名

发表评论

匿名网友

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

确定