无法在GO中解析带有冒号的标签的XML。

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

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.

&lt;summary&gt;...AIR QUALITY ALERT &lt;/summary&gt;
&lt;cap:event&gt;Air Quality Alert&lt;/cap:event&gt;

<!-- -->

type Entry struct{
    Summary    string   `xml:&quot;summary&quot;`
    Cevent     string   `xml:&quot;cap:event&quot;`
}

答案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:&quot;summary&quot;`
	Event   string `xml:&quot;event&quot;`
}

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:&quot;summary&quot;`
	Event   string `xml:&quot;urn:oasis:names:tc:emergency:cap:1.1 event&quot;`
}

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:&quot;summary&quot;`
    Cevent     string   `xml:&quot;urn:oasis:names:tc:emergency:cap:1.1:cap event&quot;`
}

Mind the space instead of : to denote the namespace. Also note that just using the namespace identifier (like xml:&quot;cap event&quot;) does not work.

Working example (https://play.golang.org/p/rjkb2esGgv):

package main

import &quot;fmt&quot;
import &quot;encoding/xml&quot;

type Entry struct{
    Summary    string   `xml:&quot;summary&quot;`
    Cevent     string   `xml:&quot;urn:oasis:names:tc:emergency:cap:1.1:cap event&quot;`
}

func main() {
	xmlString := []byte(`
        &lt;doc xmlns:cap = &#39;urn:oasis:names:tc:emergency:cap:1.1&#39;&gt;
            &lt;summary&gt;...AIR QUALITY ALERT &lt;/summary&gt;
            &lt;cap:event&gt;Air Quality Alert&lt;/cap:event&gt;
        &lt;/doc&gt;
    `)
	entry := new(Entry)
	
	if err := xml.Unmarshal(xmlString, entry); err == nil {
    	fmt.Println(entry)
    } 
}

答案3

得分: 0

你只需要转义冒号。所以将你的xml标签改为xml:&quot;cap\:event&quot;,它将按照你的期望工作。

type Entry struct{
    Summary    string   `xml:&quot;summary&quot;`
    Cevent     string   `xml:&quot;cap\:event&quot;`
}

在稍作修改的情况下,使用unmarshal示例在xml页面上进行了测试:

package main

import (
	"encoding/xml"
	"fmt"
)

func main() {
	type Email struct {
		Where string `xml:&quot;where,attr&quot;`
		Addr  string
	}
	type Address struct {
		City, State string
	}
	type Result struct {
		XMLName xml.Name `xml:&quot;Person&quot;`
		Name    string   `xml:&quot;Full\:Name&quot;`
		Phone   string
		Email   []Email
		Groups  []string `xml:&quot;Group&gt;Value&quot;`
		Address
	}
	v := Result{Name: &quot;none&quot;, Phone: &quot;none&quot;}

	data := `
		&lt;Person&gt;
			&lt;Full:Name&gt;Grace R. Emlin&lt;/Full:Name&gt;
			&lt;Company&gt;Example Inc.&lt;/Company&gt;
			&lt;Email where=&quot;home&quot;&gt;
				&lt;Addr&gt;gre@example.com&lt;/Addr&gt;
			&lt;/Email&gt;
			&lt;Email where=&#39;work&#39;&gt;
				&lt;Addr&gt;gre@work.com&lt;/Addr&gt;
			&lt;/Email&gt;
			&lt;Group&gt;
				&lt;Value&gt;Friends&lt;/Value&gt;
				&lt;Value&gt;Squash&lt;/Value&gt;
			&lt;/Group&gt;
			&lt;City&gt;Hanga Roa&lt;/City&gt;
			&lt;State&gt;Easter Island&lt;/State&gt;
		&lt;/Person&gt;
	`
	err := xml.Unmarshal([]byte(data), &amp;v)
	if err != nil {
		fmt.Printf(&quot;error: %v&quot;, err)
		return
	}
	fmt.Printf(&quot;XMLName: %#v\n&quot;, v.XMLName)
	fmt.Printf(&quot;Name: %q\n&quot;, v.Name)
	fmt.Printf(&quot;Phone: %q\n&quot;, v.Phone)
	fmt.Printf(&quot;Email: %v\n&quot;, v.Email)
	fmt.Printf(&quot;Groups: %v\n&quot;, v.Groups)
	fmt.Printf(&quot;Address: %v\n&quot;, v.Address)
}

去掉转义符号,Name将打印为"none"。使用空格代替:\:也可以工作。XML中的空格会导致解析错误,因为它显然是无效的。

英文:

You just need to escape the colon. So change your xml tag to xml:&quot;cap\:event&quot; and it will work as you expect.

type Entry struct{
Summary    string   `xml:&quot;summary&quot;`
Cevent     string   `xml:&quot;cap\:event&quot;`
}

Tested this on the xml page using the unmarshal example with minor modification;

package main
import (
&quot;encoding/xml&quot;
&quot;fmt&quot;
)
func main() {
type Email struct {
Where string `xml:&quot;where,attr&quot;`
Addr  string
}
type Address struct {
City, State string
}
type Result struct {
XMLName xml.Name `xml:&quot;Person&quot;`
Name    string   `xml:&quot;Full\:Name&quot;`
Phone   string
Email   []Email
Groups  []string `xml:&quot;Group&gt;Value&quot;`
Address
}
v := Result{Name: &quot;none&quot;, Phone: &quot;none&quot;}
data := `
&lt;Person&gt;
&lt;Full:Name&gt;Grace R. Emlin&lt;/Full:Name&gt;
&lt;Company&gt;Example Inc.&lt;/Company&gt;
&lt;Email where=&quot;home&quot;&gt;
&lt;Addr&gt;gre@example.com&lt;/Addr&gt;
&lt;/Email&gt;
&lt;Email where=&#39;work&#39;&gt;
&lt;Addr&gt;gre@work.com&lt;/Addr&gt;
&lt;/Email&gt;
&lt;Group&gt;
&lt;Value&gt;Friends&lt;/Value&gt;
&lt;Value&gt;Squash&lt;/Value&gt;
&lt;/Group&gt;
&lt;City&gt;Hanga Roa&lt;/City&gt;
&lt;State&gt;Easter Island&lt;/State&gt;
&lt;/Person&gt;
`
err := xml.Unmarshal([]byte(data), &amp;v)
if err != nil {
fmt.Printf(&quot;error: %v&quot;, err)
return
}
fmt.Printf(&quot;XMLName: %#v\n&quot;, v.XMLName)
fmt.Printf(&quot;Name: %q\n&quot;, v.Name)
fmt.Printf(&quot;Phone: %q\n&quot;, v.Phone)
fmt.Printf(&quot;Email: %v\n&quot;, v.Email)
fmt.Printf(&quot;Groups: %v\n&quot;, v.Groups)
fmt.Printf(&quot;Address: %v\n&quot;, 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.

huangapple
  • 本文由 发表于 2016年1月16日 05:57:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/34820549.html
匿名

发表评论

匿名网友

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

确定