英文:
Unable to parse xml in GO with : in tags
问题
我发现如果XML文件中的标签中包含:
,Go语言中的解析代码似乎无法正常工作。有什么见解吗?
例如,在下面的XML文件中,Summary
可以工作,但Cevent
不能。
<summary>...AIR QUALITY ALERT </summary>
<cap:event>Air Quality Alert</cap:event>
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"cap:event"`
}
英文:
I find that if tags in XML file have :
in them the unmarshal code in Go does not seem to work. Any insights ?
For example, in the XML file below, Summary
works but not Cevent
.
<summary>...AIR QUALITY ALERT </summary>
<cap:event>Air Quality Alert</cap:event>
<!-- -->
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"cap:event"`
}
答案1
得分: 8
cap
是命名空间标识符,不是标签名称的一部分。在这里,它是urn:oasis:names:tc:emergency:cap:1.1
的简写。
(这个回答看起来可能有一个关于命名空间的简洁解释:https://stackoverflow.com/questions/1181888/what-does-xmlns-in-xml-mean)
Go的encoding/xml
包对命名空间的处理不太好,但如果没有冲突的标签,你可以完全省略命名空间。
type Entry struct {
Summary string `xml:"summary"`
Event string `xml:"event"`
}
在指定事件时,特别是在不同命名空间中存在相同标签的情况下,正确的方式是使用完整的命名空间,例如:
type Entry struct {
Summary string `xml:"summary"`
Event string `xml:"urn:oasis:names:tc:emergency:cap:1.1 event"`
}
这里有一个可工作的示例:https://play.golang.org/p/ry55F2pWKY
英文:
cap
is the namespace identifier, not part of the tag name. Here it is shorthand for urn:oasis:names:tc:emergency:cap:1.1
(This answer looks like it may have a good condensed explanation of namespaces: https://stackoverflow.com/questions/1181888/what-does-xmlns-in-xml-mean)
The Go "encoding/xml" package does not handle namespaces well, but if there are no conflicting tags, you can elide the namespace altogether
type Entry struct {
Summary string `xml:"summary"`
Event string `xml:"event"`
}
The proper way to specify event, especially in the case of identical tags in different namespaces, would be with the full namespace like:
type Entry struct {
Summary string `xml:"summary"`
Event string `xml:"urn:oasis:names:tc:emergency:cap:1.1 event"`
}
Here's a working example: https://play.golang.org/p/ry55F2pWKY
答案2
得分: 4
cap
不是标签名的一部分,而是命名空间标识符(缩写为urn:oasis:names:tc:emergency:cap:1.1
,正如您在注释中提供的)。这是正确的表示方式:
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"urn:oasis:names:tc:emergency:cap:1.1 cap event"`
}
请注意,使用空格
而不是冒号:
来表示命名空间。还要注意,仅使用命名空间标识符(例如xml:"cap event"
)不起作用。
工作示例(https://play.golang.org/p/rjkb2esGgv):
package main
import "fmt"
import "encoding/xml"
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"urn:oasis:names:tc:emergency:cap:1.1 cap event"`
}
func main() {
xmlString := []byte(`
<doc xmlns:cap='urn:oasis:names:tc:emergency:cap:1.1'>
<summary>...AIR QUALITY ALERT </summary>
<cap:event>Air Quality Alert</cap:event>
</doc>
`)
entry := new(Entry)
if err := xml.Unmarshal(xmlString, entry); err == nil {
fmt.Println(entry)
}
}
英文:
cap
is not part of the tag name, but a namespace identifier (short for urn:oasis:names:tc:emergency:cap:1.1
, as you've provided in comments). This is the correct notation:
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"urn:oasis:names:tc:emergency:cap:1.1:cap event"`
}
Mind the space
instead of :
to denote the namespace. Also note that just using the namespace identifier (like xml:"cap event"
) does not work.
Working example (https://play.golang.org/p/rjkb2esGgv):
package main
import "fmt"
import "encoding/xml"
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"urn:oasis:names:tc:emergency:cap:1.1:cap event"`
}
func main() {
xmlString := []byte(`
<doc xmlns:cap = 'urn:oasis:names:tc:emergency:cap:1.1'>
<summary>...AIR QUALITY ALERT </summary>
<cap:event>Air Quality Alert</cap:event>
</doc>
`)
entry := new(Entry)
if err := xml.Unmarshal(xmlString, entry); err == nil {
fmt.Println(entry)
}
}
答案3
得分: 0
你只需要转义冒号。所以将你的xml标签改为xml:"cap\:event"
,它将按照你的期望工作。
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"cap\:event"`
}
在稍作修改的情况下,使用unmarshal示例在xml页面上进行了测试:
package main
import (
"encoding/xml"
"fmt"
)
func main() {
type Email struct {
Where string `xml:"where,attr"`
Addr string
}
type Address struct {
City, State string
}
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"Full\:Name"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
v := Result{Name: "none", Phone: "none"}
data := `
<Person>
<Full:Name>Grace R. Emlin</Full:Name>
<Company>Example Inc.</Company>
<Email where="home">
<Addr>gre@example.com</Addr>
</Email>
<Email where='work'>
<Addr>gre@work.com</Addr>
</Email>
<Group>
<Value>Friends</Value>
<Value>Squash</Value>
</Group>
<City>Hanga Roa</City>
<State>Easter Island</State>
</Person>
`
err := xml.Unmarshal([]byte(data), &v)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("XMLName: %#v\n", v.XMLName)
fmt.Printf("Name: %q\n", v.Name)
fmt.Printf("Phone: %q\n", v.Phone)
fmt.Printf("Email: %v\n", v.Email)
fmt.Printf("Groups: %v\n", v.Groups)
fmt.Printf("Address: %v\n", v.Address)
}
去掉转义符号,Name将打印为"none"。使用空格代替:
或\:
也可以工作。XML中的空格会导致解析错误,因为它显然是无效的。
英文:
You just need to escape the colon. So change your xml tag to xml:"cap\:event"
and it will work as you expect.
type Entry struct{
Summary string `xml:"summary"`
Cevent string `xml:"cap\:event"`
}
Tested this on the xml page using the unmarshal example with minor modification;
package main
import (
"encoding/xml"
"fmt"
)
func main() {
type Email struct {
Where string `xml:"where,attr"`
Addr string
}
type Address struct {
City, State string
}
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"Full\:Name"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
v := Result{Name: "none", Phone: "none"}
data := `
<Person>
<Full:Name>Grace R. Emlin</Full:Name>
<Company>Example Inc.</Company>
<Email where="home">
<Addr>gre@example.com</Addr>
</Email>
<Email where='work'>
<Addr>gre@work.com</Addr>
</Email>
<Group>
<Value>Friends</Value>
<Value>Squash</Value>
</Group>
<City>Hanga Roa</City>
<State>Easter Island</State>
</Person>
`
err := xml.Unmarshal([]byte(data), &v)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("XMLName: %#v\n", v.XMLName)
fmt.Printf("Name: %q\n", v.Name)
fmt.Printf("Phone: %q\n", v.Phone)
fmt.Printf("Email: %v\n", v.Email)
fmt.Printf("Groups: %v\n", v.Groups)
fmt.Printf("Address: %v\n", v.Address)
}
Remove the escape and it will print "none" for Name. Use a space instead of :
or \:
and it will also work. A space in the xml will cause a parse error because it's invalid apparently.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论