在使用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>ref,attr"
,但是因为“链条无法使用attr标志”而失败。
请参阅以下示例代码。 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
}
答案 0 :(得分:3)
简而言之,你不能直接这样做。绕过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
结构是按照您希望的那样建模的。有效载荷解码后,您可以根据需要使用它来初始化Way
变量...
旁注: // Why can't I return nil, err?
您无法返回nil
,因为Way
不是指针或界面,因此nil
不是有效的值。< / p>