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

时间:2019-01-29 14:37:24

标签: xml parsing go

我是Golang的新手,使用同名嵌套节点解析XML对我来说太困难了。这是从第三方API中提取的XML:

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

我需要解析它,所以我会有这样的输出:

&{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}]}

这是我的代码:

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\n\n", 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>`

我不知道如何将time属性插入Rates对象。任何帮助将不胜感激。

这里是golang playground

2 个答案:

答案 0 :(得分:1)

您可以实施自定义xml.Unmarshaler以获得所需的结果。

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

答案 1 :(得分:0)

我同意mkopriva的回答,但无法发表评论,因此我要添加回复。

确保使用XSD之类的东西来信任XML或事先对其进行验证/清除。这应该是做了两个安全原因,以及能够回过头来,看看数据你“解组”是正确的,因为当你正在处理XML的巨额资金,它的一些必然被打破。