问题
I have the following xml "file":
<pinnacle_line_feed>
<PinnacleFeedTime>1439954818555</PinnacleFeedTime>
<lastContest>34317132</lastContest>
<lastGame>218491030</lastGame>
<events>
<event>
<event_datetimeGMT>2015-08-21 09:50</event_datetimeGMT>
<gamenumber>483406220</gamenumber>
<sporttype>Aussie Rules</sporttype>
<league>AFL</league>
<IsLive>No</IsLive>
<participants>
<participant>
<participant_name>Hawthorn Hawks</participant_name>
<contestantnum>1251</contestantnum>
<rotnum>1251</rotnum>
<visiting_home_draw>Visiting</visiting_home_draw>
</participant>
<participant>
<participant_name>Port Adelaide Power</participant_name>
<contestantnum>1252</contestantnum>
<rotnum>1252</rotnum>
<visiting_home_draw>Home</visiting_home_draw>
</participant>
</participants>
<periods></periods>
</event>
</events>
</pinnacle_line_feed>
I am attempting to parse this with Golang, and have written the below thus far:
package main
import (
"fmt"
"encoding/xml"
)
type Participant struct {
XMLName xml.Name `xml:"participant"`
participant_name string `xml:"participant_name"`
contestantnum int `xml:"contestantnum"`
rotnum int `xml:"rotnum"`
visiting_home_draw string `xml:"visiting_home_draw"`
}
type Event struct {
XMLName xml.Name `xml:"event"`
event_datetimeGMT string `xml:"event_datetimeGMT"`
gamenumber string `xml:"gamenumber"`
sporttype string `xml:"sporttype"`
league string `xml:"league"`
IsLive string `xml:"IsLive"`
Participant []Participant `xml:"participant"`
}
type Events struct {
XMLName xml.Name `xml:"events"`
Event []Event `xml:"event"`
}
type Pinnacle_Line_Feed struct {
XMLName xml.Name `xml:"pinnacle_line_feed"`
PinnacleFeedTime string `xml:"PinnacleFeedTime"`
lastContest string `xml:"lastContest"`
lastGame string `xml:"lastGame"`
Events []Events `xml:"events"`
}
Frankly, I have researched quite a bit on deep nested xml parsing in Golang, and I haven't found much to help with the Unmarshal portion of this code. Ideally, the code would return something similar to a python dictionary, such as,
{event_datetimeGMT: 2015-08-21, gamenumber: 483406220, ... , visiting_home_draw: "Home"}
EDIT:
Based on Nicolas's comment below, I added the following. This runs without error, but produces an empty result.
func main() {
pinny_xml := `
<pinnacle_line_feed>
<PinnacleFeedTime>1439954818555</PinnacleFeedTime>
<lastContest>34317132</lastContest>
<lastGame>218491030</lastGame>
<events>
<event>
<event_datetimeGMT>2015-08-21 09:50</event_datetimeGMT>
<gamenumber>483406220</gamenumber>
<sporttype>Aussie Rules</sporttype>
<league>AFL</league>
<IsLive>No</IsLive>
<participants>
<participant>
<participant_name>Hawthorn Hawks</participant_name>
<contestantnum>1251</contestantnum>
<rotnum>1251</rotnum>
<visiting_home_draw>Visiting</visiting_home_draw>
</participant>
<participant>
<participant_name>Port Adelaide Power</participant_name>
<contestantnum>1252</contestantnum>
<rotnum>1252</rotnum>
<visiting_home_draw>Home</visiting_home_draw>
</participant>
</participants>
<periods></periods>
</event>
</events>
</pinnacle_line_feed>
`
xmlReader := bytes.NewReader([]byte(pinny_xml))
yourPinnacleLineFeed := new(Pinnacle_Line_Feed)
if err := xml.NewDecoder(xmlReader).Decode(yourPinnacleLineFeed); err != nil {
return // or log.Panic(err.Error()) if in main
}
}
回答1:
You can do it like this :
xmlReader := bytes.NewReader([]byte(your_xml_as_a_string_here))
yourPinnacleLineFeed := new(Pinnacle_Line_Feed)
if err := xml.NewDecoder(xmlReader).Decode(yourPinnacleLineFeed); err != nil {
return // or log.Panic(err.Error()) if in main
}
This is if your xml "file" is a string. If you're getting it from the internet (as the body of an http response for instance), resp.Body is already going to satisfy a Reader, so you can skip the first line. If you're opening a real file on the OS, you can also open it as a Reader, same thing.
EDIT: Two more things:
- You can nest the structs and drop the xml.Name fields for simplicity and clarity
- I also noticed you forgot the participants level in the structs, leading for no participants to be unmarshaled
Here's a more simple version that works, with an optional function to check what you have inside the results :
package main
import (
"bytes"
"encoding/json"
"encoding/xml"
"fmt"
"log"
)
type Pinnacle_Line_Feed struct {
PinnacleFeedTime string `xml:"PinnacleFeedTime"`
LastContest string `xml:"lastContest"`
LastGame string `xml:"lastGame"`
Events struct {
Event []struct {
Event_datetimeGMT string `xml:"event_datetimeGMT"`
Gamenumber string `xml:"gamenumber"`
Sporttype string `xml:"sporttype"`
League string `xml:"league"`
IsLive string `xml:"IsLive"`
Participants struct {
Participant []struct {
Participant_name string `xml:"participant_name"`
Contestantnum int `xml:"contestantnum"`
Rotnum int `xml:"rotnum"`
Visiting_home_draw string `xml:"visiting_home_draw"`
} `xml:"participant"`
} `xml:"participants"`
} `xml:"event"`
} `xml:"events"`
}
func main() {
pinny_xml := `
<pinnacle_line_feed>
<PinnacleFeedTime>1439954818555</PinnacleFeedTime>
<lastContest>34317132</lastContest>
<lastGame>218491030</lastGame>
<events>
<event>
<event_datetimeGMT>2015-08-21 09:50</event_datetimeGMT>
<gamenumber>483406220</gamenumber>
<sporttype>Aussie Rules</sporttype>
<league>AFL</league>
<IsLive>No</IsLive>
<participants>
<participant>
<participant_name>Hawthorn Hawks</participant_name>
<contestantnum>1251</contestantnum>
<rotnum>1251</rotnum>
<visiting_home_draw>Visiting</visiting_home_draw>
</participant>
<participant>
<participant_name>Port Adelaide Power</participant_name>
<contestantnum>1252</contestantnum>
<rotnum>1252</rotnum>
<visiting_home_draw>Home</visiting_home_draw>
</participant>
</participants>
<periods></periods>
</event>
</events>
</pinnacle_line_feed>
`
xmlReader := bytes.NewReader([]byte(pinny_xml))
yourPinnacleLineFeed := new(Pinnacle_Line_Feed)
if err := xml.NewDecoder(xmlReader).Decode(yourPinnacleLineFeed); err != nil {
log.Panic(err.Error())
}
printX(yourPinnacleLineFeed)
}
func printX(x interface{}) (err error) {
var xBytes []byte
xBytes, err = json.MarshalIndent(x, "", " ")
if err != nil {
return
}
fmt.Println(string(xBytes))
return
}
回答2:
You need to uppercase all of the fields in your structs. The xml decoder needs the fields to be exported in order to work properly. Go playground here.
来源:https://stackoverflow.com/questions/32125816/unmarshaling-xml-in-go