英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论