【问题标题】:Parsing sub-element's attribute directly into Go struct将子元素的属性直接解析为 Go 结构体
【发布时间】:2016-03-29 17:18:07
【问题描述】:

在使用 Go 解析 XML 时,如何将嵌套元素的属性直接读取到我的结构中?

我的 XML 如下所示。它是 OpenStreetMap 格式的一部分:

<way id="123" >
        <nd ref="101"/>
        <!-- Lots of nd elements repeated -->
        <nd ref="109"/>
</way>

我有

type Way struct {
    Nodes []NodeRef `xml:"nd"`
}

与

type NodeRef struct {
    Ref int `xml:"ref,attr"`
}

但我希望能够做到

type Way struct {
    Nodes []int `???`
}

直接。

Unmarshalling 上的文档对我没有帮助。我尝试过使用xml:"nd&gt;ref,attr",但失败并显示“chain not valid with attr flag”。

请看下面的示例代码。 Run the code in Go Playground

package main

import (
    "encoding/xml"
    "fmt"
    "io"
    "os"
    "strings"
)

func main() {
    data := `
        <way id="5090250" >
        <nd ref="822403"/>
        <nd ref="21533912"/>
        <nd ref="821601"/>
        <nd ref="21533910"/>
        <nd ref="135791608"/>
        <nd ref="333725784"/>
        <nd ref="333725781"/>
        <nd ref="333725774"/>
        <nd ref="333725776"/>
        <nd ref="823771"/>
      </way>
    `

    r := strings.NewReader(data)
    way, err := ReadWay(r)
    if err != nil {
        fmt.Println("Could not read", err)
        os.Exit(1)
    }

    fmt.Println(way)
}

// I'd like to get rid of this nested struct.
type NodeRef struct {
    Ref int `xml:"ref,attr"`
}

type Way struct {
    ID int `xml:"id,attr"`
    // How can I write all <nd ref="123"/> directly into Nodes []int?
    Nodes []NodeRef `xml:"nd"`
}

func ReadWay(reader io.Reader) (Way, error) {
    var way Way
    if err := xml.NewDecoder(reader).Decode(&way); err != nil {
        return way, err // Why can't I return nil, err?
    }
    return way, nil
}

【问题讨论】:

    标签: xml go xml-parsing openstreetmap


    【解决方案1】:

    简而言之,您不能直接这样做。绕过 XML 结构的常见模式是实现xml.Unmarshaler 接口。这是一个例子:

    type Way struct {
        ID    int 
        Nodes []int
    }
    
    func (w *Way) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
        var payload struct {
            ID    int `xml:"id,attr"`
            Nodes []struct {
                Ref int `xml:"ref,attr"`
            } `xml:"nd"`
        }   
    
        err := d.DecodeElement(&payload, &start)
        if err != nil {
            return err 
        }   
    
        w.ID = payload.ID
        w.Nodes = make([]int, 0, len(payload.Nodes))
    
        for _, node := range payload.Nodes {
            w.Nodes = append(w.Nodes, node.Ref)
        }   
    
        return nil 
    }
    

    这里,payload 变量是根据您的 XML 数据建模的,而 Way 结构是根据您的需要建模的。一旦payload被解码,你就可以用它来初始化Way变量了……

    旁注: // Why can't I return nil, err?

    您不能返回nil,因为Way 既不是指针也不是接口,因此nil 不是它的有效值。

    【讨论】:

    猜你喜欢
    • 2013-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-06
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多