drvfqr5609
drvfqr5609
2019-01-29 14:37
浏览 452

如何解析具有相同名称的嵌套节点的XML?

I'm new to Golang and parsing XML with nested nodes of the same name is too difficult to me. This is a XML pulled from a third party API:

<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time="2019-01-28">
            <Cube currency="USD" rate="1.1418"/>
            <Cube currency="JPY" rate="124.94"/>
            <Cube currency="BGN" rate="1.9558"/>
        </Cube>
        <Cube time="2019-01-25">
            <Cube currency="USD" rate="1.1346"/>
            <Cube currency="JPY" rate="124.72"/>
            <Cube currency="BGN" rate="1.9558"/>
        </Cube>
    </Cube>
</gesmes:Envelope>

I need to parse it so I have an output like this:

&{Rates:[{Currency:USD Rate:1.1418 Date:2019-01-28} {Currency:JPY Rate:124.94 Date:2019-01-28} {Currency:BGN Rate:1.9558 Date:2019-01-28} {Currency:USD Rate:1.1346 Date:2019-01-25} {Currency:JPY Rate:124.72 Date:2019-01-25} {Currency:BGN Rate:1.9558 Date:2019-01-25}]}

And here's my code:

package main

import (
    "encoding/xml"
    "fmt"
)


type Rate struct {
    Currency  string `xml:"currency,attr"`
    Rate      string `xml:"rate,attr"`
    Date    string `xml:"time,attr"`
}

type Rates struct {
    Rates []Rate `xml:"Cube>Cube>Cube"`
}

func main() {
    v := &Rates{}
    if err := xml.Unmarshal([]byte(src), v); err != nil {
        panic(err)
    }
    fmt.Printf("%+v

", v)
}

const src = `<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time="2019-01-28">
            <Cube currency="USD" rate="1.1418"/>
            <Cube currency="JPY" rate="124.94"/>
            <Cube currency="BGN" rate="1.9558"/>
        </Cube>
        <Cube time="2019-01-25">
            <Cube currency="USD" rate="1.1346"/>
            <Cube currency="JPY" rate="124.72"/>
            <Cube currency="BGN" rate="1.9558"/>
        </Cube>
    </Cube>
</gesmes:Envelope>`

I'm out of ideas how to insert time attribute into Rates object. Any help would be appreciated.

Here it is in golang playground

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • down101102
    down101102 2019-01-29 23:54
    已采纳

    You could implement a custom xml.Unmarshaler to get the results you want.

    type Rate struct {
        Currency string `xml:"currency,attr"`
        Rate     string `xml:"rate,attr"`
        Date     string `xml:"time,attr"`
    }
    
    type Rates struct {
        Rates RateList `xml:"Cube>Cube"`
    }
    
    type RateList []Rate
    
    func (ls *RateList) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
        date := start.Attr[0].Value
    
        for {
            tok, err := d.Token()
            if err != nil {
                if err == io.EOF {
                    return nil
                }
                return err
            }
    
            if se, ok := tok.(xml.StartElement); ok {
                rate := Rate{Date: date}
                if err := d.DecodeElement(&rate, &se); err != nil {
                    return err
                }
    
                *ls = append(*ls, rate)
            }
        }
    }
    

    Go Playground

    点赞 评论
  • dorflv5944
    dorflv5944 2019-01-30 10:18

    I agree with mkopriva's answer, but cannot comment so I'm adding a reply.

    Make sure that you either trust the XML, or that you validate/sanitize it beforehand, with something like XSD. This should be done for both security reasons, as well as to be able to look back and see if the data you "Unmarshalled" is correct, because when you're processing huge amounts of XML, some of it is bound to be broken.

    点赞 评论

相关推荐