Reputation: 105
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"`
}
Upvotes: 6
Views: 1834
Reputation: 109388
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: 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
Upvotes: 8
Reputation: 38004
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)
}
}
Upvotes: 4
Reputation: 48096
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>[email protected]</Addr>
</Email>
<Email where='work'>
<Addr>[email protected]</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.
Upvotes: 0