結論から書くと、ちゃんと構造体でラップしましょう、ということです。
出ないと書き出したXMLがちゃんと読み込まれなくて ( ;゚皿゚)ノシΣバンバン!! ってすることになります。
やらかしたこと
次のように、構造体とそのスライスを用意して、XMLに変換したわけです。
package main
import "encoding/xml"
import "fmt"
type Item struct {
XMLName xml.Name `xml:"item"`
ID string `xml:"id,attr"`
Name string `xml:"name"`
Value string `xml:"value"`
}
type Items []Item
func main() {
items := Items{
Item{
ID: "001",
Name: "AA1",
Value: "|ω・`)ノ ヤァ",
},
Item{
ID: "002",
Name: "AA2",
Value: "|д゚)チラッ",
},
}
if buf, err := xml.MarshalIndent(items, "", " "); err != nil {
panic(err)
} else {
fmt.Print(xml.Header)
fmt.Println(string(buf))
}
}
実行すると次のようなXMLを得られます。
xml version="1.0" encoding="UTF-8"
<item id="001">
<name>AA1</name>
<value>|ω・`)ノ ヤァ</value>
</item>
<item id="002">
<name>AA2</name>
<value>|д゚)チラッ</value>
</item>
この時点ですでになんか怪しいことにお気づきでしょうか。そう、ルート要素が複数あるということに。
さて、これを以下のコードで読み込むと( ゚д゚)します。
package main
import "encoding/xml"
import "fmt"
type Item struct {
XMLName xml.Name `xml:"item"`
ID string `xml:"id,attr"`
Name string `xml:"name"`
Value string `xml:"value"`
}
type Items []Item
func main() {
items := make(Items, 0)
doc := `<?xml version="1.0" encoding="UTF-8"?>
<item id="001">
<name>AA1</name>
<value>|ω・`)ノ ヤァ</value>
</item>
<item id="002">
<name>AA2</name>
<value>|д゚)チラッ</value>
</item>
`
if err := xml.Unmarshal([]byte(doc), &items); err != nil {
panic(err)
} else {
for _, item := range items {
fmt.Println(item)
}
}
}
以下出力結果。
{{ item} 001 AA1 |ω・`)ノ ヤァ}
二要素目が闇に消えましたね ( ・´ー・`)
原因
たぶんルート要素がいっぱいあるせい。つまり正しいXMLになってない。
正しい解決法
なので、ちゃんと構造体でラップしましょう、そうしましょう。
package main
import "encoding/xml"
import "fmt"
type Item struct {
XMLName xml.Name `xml:"item"`
ID string `xml:"id,attr"`
Name string `xml:"name"`
Value string `xml:"value"`
}
type Items struct {
XMLName xml.Name `xml:"items"`
Items []Item `xml:"item"`
}
func main() {
items := &Items{
Items: []Item{
Item{
ID: "001",
Name: "AA1",
Value: "|ω・`)ノ ヤァ",
},
Item{
ID: "002",
Name: "AA2",
Value: "|д゚)チラッ",
},
},
}
if buf, err := xml.MarshalIndent(items, "", " "); err != nil {
panic(err)
} else {
fmt.Print(xml.Header)
fmt.Println(string(buf))
}
}
xml version="1.0" encoding="UTF-8"
<items>
<item id="001">
<name>AA1</name>
<value>|ω・`)ノ ヤァ</value>
</item>
<item id="002">
<name>AA2</name>
<value>|д゚)チラッ</value>
</item>
</items>
デコードする方のコード
package main
import "encoding/xml"
import "fmt"
type Item struct {
XMLName xml.Name `xml:"item"`
ID string `xml:"id,attr"`
Name string `xml:"name"`
Value string `xml:"value"`
}
type Items struct {
XMLName xml.Name `xml:"items"`
Items []Item `xml:"item"`
}
func main() {
items := Items{}
doc := `<?xml version="1.0" encoding="UTF-8"?>
<items>
<item id="001">
<name>AA1</name>
<value>|ω・`)ノ ヤァ</value>
</item>
<item id="002">
<name>AA2</name>
<value>|д゚)チラッ</value>
</item>
</items>
`
if err := xml.Unmarshal([]byte(doc), &items); err != nil {
panic(err)
} else {
for _, item := range items.Items {
fmt.Println(item)
}
}
}
デコード結果
{{ item} 001 AA1 |ω・`)ノ ヤァ}
{{ item} 002 AA2 |д゚)チラッ}
ダメな解決方法
構造体作りたくないでござる、スライスはスライスのままにしたいでござる、みたいな人 *1 のためにたぶん間違った解決方法を。
その方法は xml.Marshaler / xml.Unmarshalerを実装して、ルート要素を無理やり作る、というのもですが。
package main
import "encoding/xml"
import "fmt"
type Item struct {
XMLName xml.Name `xml:"item"`
ID string `xml:"id,attr"`
Name string `xml:"name"`
Value string `xml:"value"`
}
type Items []Item
func (self Items) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
root := struct {
Items []Item `xml:"item"`
}{
Items: self,
}
start.Name.Local = "items"
return e.EncodeElement(&root, start)
}
func main() {
items := Items{
Item{
ID: "001",
Name: "AA1",
Value: "|ω・`)ノ ヤァ",
},
Item{
ID: "002",
Name: "AA2",
Value: "|д゚)チラッ",
},
}
if buf, err := xml.MarshalIndent(items, "", " "); err != nil {
panic(err)
} else {
fmt.Print(xml.Header)
fmt.Println(string(buf))
}
}
デコード側
package main
import "encoding/xml"
import "fmt"
type Item struct {
XMLName xml.Name `xml:"item"`
ID string `xml:"id,attr"`
Name string `xml:"name"`
Value string `xml:"value"`
}
type Items []Item
func (self *Items) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
root := struct {
Items []Item `xml:"item"`
}{}
if err := d.DecodeElement(&root, &start); err != nil {
return err
} else {
*self = root.Items
return nil
}
}
func main() {
items := Items{}
doc := `<?xml version="1.0" encoding="UTF-8"?>
<items>
<item id="001">
<name>AA1</name>
<value>|ω・`)ノ ヤァ</value>
</item>
<item id="002">
<name>AA2</name>
<value>|д゚)チラッ</value>
</item>
</items>
`
if err := xml.Unmarshal([]byte(doc), &items); err != nil {
panic(err)
} else {
for _, item := range items {
fmt.Println(item)
}
}
}
自分自身のスライスの参照先を書き換えるとか ((((;゚Д゚))))ガクガクブルブル しますね!!