douqianbiao4216 2015-08-20 18:34
浏览 35
已采纳

在Go中解组XML

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
        }
}

</div>
  • 写回答

2条回答 默认 最新

  • doucai9270 2015-08-20 19:15
    关注

    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
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?