2

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
        }
}
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
amachure
  • 43
  • 2
  • 8

2 Answers2

2

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
}
Nicolas Marshall
  • 4,186
  • 9
  • 36
  • 54
  • Thanks Nicolas! I edited my comment based on your response, and it seems that this will run without issue, but the result is simply empty. – amachure Aug 20 '15 at 19:34
  • Looks like I'm a bit late, and that Jay Crumb is right ! Uppercase first letters in your structs all the way ! – Nicolas Marshall Aug 20 '15 at 20:56
1

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.

Jay Crumb
  • 141
  • 1
  • 5