Reputation: 6994
So I am trying to Unmarshal or Decode some xml into a type (I am still not entirely clear on what the difference is), and I don't seem to be able to specify the outermost type (in this case <people>
). When I try to specify this tag, instead of getting an error, the Marshalled value does not contain any of the content I am expecting. How do you specify the outermost tag and why doesn't the second assignment have the expected behavior?
package main
import "fmt"
import "encoding/xml"
import "log"
var data string = `
<people>
<person>
<id>46</id>
<name>John Smith</name>
</person>
<person>
<id>3007</id>
<name>Joe Smith</name>
</person>
</people>
`
type Person struct {
Id int `xml:"id"`
Name string `xml:"name"`
}
type People struct {
PersonList []Person `xml:"person"`
}
type Response struct {
PeopleItem People `xml:"people"`
}
func main() {
// parsing People
// cannot specify outermost tag <people></people>
var people People
err := xml.Unmarshal([]byte(data), &people)
if err != nil {
log.Fatal(err)
}
fmt.Println(people)
// prints "{[{46 John Smith} {3007 Joe Smith}]}"
// which is reasonable
// attempting to parse entire response, yields struct of struct of empty slice
var response Response
err = xml.Unmarshal([]byte(data), &response)
if err != nil {
log.Fatal(err)
}
// response is struct of struct of empty array
// why does this happen?
fmt.Println(response)
// why does this print "{{[]}}" ?
}
Upvotes: 3
Views: 1875
Reputation: 3553
You can do this without hacking the incoming data, you use the special XMLName xml.Name
field to set the outside tag and then use xml:",chardata"
to access it's contents.
Here is an example: Try it on the go playground
package main
import (
"encoding/xml"
"fmt"
)
type simpleInt struct {
XMLName xml.Name `xml:"integer"`
Int int `xml:",chardata"`
}
type simpleString struct {
XMLName xml.Name `xml:"stringtag"`
String string `xml:",chardata"`
}
type simpleBoolean struct {
XMLName xml.Name `xml:"boolean"`
Boolean bool `xml:",chardata"`
}
func main() {
bint := []byte("<integer>1138</integer>")
bstring := []byte("<stringtag>Caimeo</stringtag>")
btrue := []byte("<boolean>true</boolean>")
bfalse := []byte("<boolean>false</boolean>")
i := simpleInt{}
xml.Unmarshal(bint, &i)
fmt.Println(i, i.Int)
s := simpleString{}
xml.Unmarshal(bstring, &s)
fmt.Println(s, s.String)
m := simpleBoolean{}
xml.Unmarshal(btrue, &m)
fmt.Println(m, m.Boolean)
xml.Unmarshal(bfalse, &m)
fmt.Println(m, m.Boolean)
}
Upvotes: 2
Reputation: 36179
Here's a lazy solution: add a new, unique top level element:
var response Response
err = xml.Unmarshal([]byte("<foo>"+data+"</foo>"), &response)
Upvotes: 1