Xml 解析子元素';将属性直接放入Go结构中

Xml 解析子元素';将属性直接放入Go结构中,xml,go,xml-parsing,openstreetmap,Xml,Go,Xml Parsing,Openstreetmap,在使用Go解析XML时,如何将嵌套元素的属性直接读取到结构中 我的XML如下所示。它是OpenStreetMap格式的一部分: <way id="123" > <nd ref="101"/> <!-- Lots of nd elements repeated --> <nd ref="109"/> </way> 与 但我希望能够做到 type Way struct { Nodes

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

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

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

但我希望能够做到

type Way struct {
    Nodes []int `???`
}
直接的

关于的文档对我没有帮助。我尝试过使用
xml:“nd>ref,attr”
,但由于“chain not valid with attr flag”而失败

请参阅下面的示例代码

主程序包
进口(
“编码/xml”
“fmt”
“io”
“操作系统”
“字符串”
)
func main(){
数据:=`
`
r:=strings.NewReader(数据)
通道,错误:=读通道(r)
如果错误!=零{
fmt.Println(“无法读取”,错误)
操作系统退出(1)
}
fmt.Println(道路)
}
//我想去掉这个嵌套结构。
类型NodeRef结构{
Ref int`xml:“Ref,attr”`
}
类型方式结构{
ID int`xml:“ID,attr”`
//如何将所有数据直接写入节点[]int?
Nodes[]NodeRef`xml:“nd”`
}
func读卡器通道(读卡器io.reader)(通道,错误){
var方式
如果错误:=xml.NewDecoder(reader).Decode(&way);错误!=nil{
返回方式,呃//为什么我不能返回零,呃?
}
回程,零
}

简而言之,你不能直接这么做。绕过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
struct是按照您希望的方式建模的。一旦有效负载被解码,您就可以使用它来初始化
Way
变量,如您所愿

旁注:
//为什么我不能返回nil,err?


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

有关此内容的文档如下所示,以供将来参考:
type Way struct {
    Nodes []int `???`
}
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
}
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 
}