2016-03-29 12 views
0

Goを使ってXMLを構文解析するとき、ネストされた要素の属性を構造体に直接読み込むにはどうすればよいですか?サブ要素の属性をGo構造体に直接構文解析する

私のXMLは以下のようになります。私は

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

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

を持っていますが、私は直接

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

を行うことができるようにしたいと思い

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

:それはOpenStreetMapのフォーマットの一部です。

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 
} 

答えて

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 
} 

あなたはそれになりたいようWay構造体がモデル化されている間、​​変数は、XMLデータをモデルにしています。ペイロードがデコードされたら、あなたが望むように、あなたがWay変数を初期化するために使用することができ...

サイドノート:// Why can't I return nil, err?

Wayがポインタまたはインターフェイスのいずれかではありませんので、あなたがnilを返すことはできません。したがって、nilは有効な値ではありません。

+0

今後の参考資料は、こちらのドキュメントをご覧ください:https://golang.org/pkg/encoding/xml/#Unmarshaler – Unapiedra

関連する問題