英文:
Dealing with namespaces while parsing XML in Go
问题
我正在尝试在Go中解析一段XML代码:
package main
import (
"encoding/xml"
"fmt"
)
type XML struct {
Foo string `xml:"foo"`
}
func main() {
rawXML := []byte(`
<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`)
x := new(XML)
xml.Unmarshal(rawXML, x)
fmt.Printf("foo: %s\n", x.Foo)
}
这将输出:
foo: B
而我期望它输出:
foo: A
如何获取第一个foo
标签的内容(即没有命名空间的标签)?
英文:
I am trying to parse a piece if XML in Go:
package main
import (
"encoding/xml"
"fmt"
)
type XML struct {
Foo string `xml:"foo"`
}
func main() {
rawXML := []byte(`
<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`)
x := new(XML)
xml.Unmarshal(rawXML, x)
fmt.Printf("foo: %s\n", x.Foo)
}
This outputs:
foo: B
While I expected it to produce:
foo: A
How do I get content of the first foo
tag (i.e. one without namespace)?
答案1
得分: 8
我不认为XML解码器可以使用结构标签指定一个元素不应该有命名空间。但是我知道它可以为您检索有关命名空间的信息,然后您可以在数据后进行后处理以获得相同的结果:
package main
import (
"encoding/xml"
"fmt"
)
type Foo struct {
XMLName xml.Name
Data string `xml:",chardata"`
}
type XML struct {
Foo []Foo `xml:"foo"`
}
func main() {
rawXML := []byte(`
<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`)
x := new(XML)
xml.Unmarshal(rawXML, x)
//fmt.Printf("foo: %#v\n", x)
for _, el := range x.Foo {
if el.XMLName.Space == "" {
fmt.Printf("non namespaced foo %q", el.Data)
}
}
}
http://play.golang.org/p/aDEFPmHPc0
英文:
I don't think the xml decoder can specify an element should have no namespace with struct tags. But I do know that it can retrieve the information about the namespaces for you and you could then post process the data after to get the same result:
package main
import (
"encoding/xml"
"fmt"
)
type Foo struct {
XMLName xml.Name
Data string `xml:",chardata"`
}
type XML struct {
Foo []Foo `xml:"foo"`
}
func main() {
rawXML := []byte(`
<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`)
x := new(XML)
xml.Unmarshal(rawXML, x)
//fmt.Printf("foo: %#v\n", x)
for _, el := range x.Foo {
if el.XMLName.Space == "" {
fmt.Printf("non namespaced foo %q", el.Data)
}
}
}
答案2
得分: 4
你的xml文档中有两个连续的值。你的结构体只有一个值的空间。xml解析器会解析第一个值,然后用第二个值覆盖它。
将结构体中的Foo改为切片,然后你就可以得到两个值。
http://play.golang.org/p/BRgsuMQ7rK
package main
import (
"encoding/xml"
"fmt"
)
type XML struct {
Foo []string `xml:"foo"`
}
func main() {
rawXML := []byte(`
<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`)
x := new(XML)
xml.Unmarshal(rawXML, x)
fmt.Printf("foo: %s\n", x.Foo[0])
fmt.Printf("both: %v\n", x.Foo)
}
英文:
You have two values in series in your xml document. You only have room for one value in your struct. The xml parser is parsing the first one and then overwriting it with the second one.
Change Foo to a slice in the struct and then you'll get both values.
http://play.golang.org/p/BRgsuMQ7rK
package main
import (
"encoding/xml"
"fmt"
)
type XML struct {
Foo []string `xml:"foo"`
}
func main() {
rawXML := []byte(`
<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`)
x := new(XML)
xml.Unmarshal(rawXML, x)
fmt.Printf("foo: %s\n", x.Foo[0])
fmt.Printf("both: %v\n", x.Foo)
}
答案3
得分: 1
xml:"foo"
选择器语法可以使用可选的命名空间xml:"ns foo"
,但问题是它不支持选择没有命名空间的情况。
一种修复方法是使用xml.Decoder.DefaultSpace
来为无命名空间的标签分配一个命名空间,然后可以使用xml:"<ns> <tag>"
语法进行选择:
https://play.golang.org/p/1UggvqLFT9x
import (
"encoding/xml"
"strings"
"fmt"
)
type Doc struct {
Foo string `xml:"_ foo"` // <-- <foo> will now be <_:foo>
NsFoo string `xml:"ns foo"`
}
var input = `<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`
func main() {
decoder := xml.NewDecoder(strings.NewReader(input))
decoder.DefaultSpace = "_"
doc := &Doc{}
decoder.Decode(doc)
fmt.Printf("<foo>: %#v\n", doc.Foo)
fmt.Printf("<ns:foo>: %#v\n", doc.NsFoo)
}
输出结果:
<foo>: A
<ns:foo>: B
英文:
The xml:"foo"
selector syntax takes an optional namespace xml:"ns foo"
, but the problem is that it doesn't support a way to select for no namespace.
One fix is to use xml.Decoder.DefaultSpace
to simply assign a namespace to non-namespaced tags that you can now select using xml:"<ns> <tag>"
syntax:
https://play.golang.org/p/1UggvqLFT9x
import (
"encoding/xml"
"strings"
"fmt"
)
type Doc struct {
Foo string `xml:"_ foo"` // <-- <foo> will now be <_:foo>
NsFoo string `xml:"ns foo"`
}
var input = `<xml>
<foo>A</foo>
<ns:foo>B</ns:foo>
</xml>`
func main() {
decoder := xml.NewDecoder(strings.NewReader(input))
decoder.DefaultSpace = "_"
doc := &Doc{}
decoder.Decode(doc)
fmt.Printf("<foo>: %#v\n", doc.Foo)
fmt.Printf("<ns:foo>: %#v\n", doc.NsFoo)
}
Prints:
<foo>: A
<ns:foo>: B
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论