golangでxmlをパースする

Go言語でxmlをパースしようとしてけっこうハマったのでメモを残しておきます。

Xmlをパースする手順

1. 構造体を定義する

たとえばこんなxmlがあるとする。

str := `
<?xml version="1.0" encoding="UTF-8"?>
<Nicovideo>
    <thumb>
        <title>動画タイトル</title>
        <length>12:59</length>
    </thumb>
</Nicovideo>
`

そしたらこんな構造体を用意してあげる。

type Nicovideo struct {
	Thumb Thumb `xml:"thumb"`
}
type Thumb struct {
	Title string `xml:"title"`
	Length string `xml:"length"`
}

このとき注意することは2点。

  • 構造体のフィールド名を先頭大文字とすること
  • 構造体フィールド名とxmlの要素名が異なる場合(大文字小文字も区別される)は「'xml:"title"'」のようにどの要素を指すか明記する。

また、構造体を定義する際、欲しい要素がtitleだけであるなら、Lengthフィールドは定義する必要はない。

2. 構造体を初期化する

nicoXml := Nicovideo{Thumb{"", ""}}

3. パース関数を呼び出す

err := xml.Unmarshal([]byte(str), &nicoXml)

4. パースしたものを参照する

fmt.Println(nicoXml)
fmt.Println("title: " + nicoXml.Thumb.Title)
fmt.Println("length: " + nicoXml.Thumb.Length)

構造体を通してアクセスする。

サンプルコード

package main

import (
	"log"
	"fmt"
	"encoding/xml"
)

func main() {

	str := `
	<?xml version="1.0" encoding="UTF-8"?>
	<Nicovideo>
		<thumb>
			<title>動画タイトル</title>
			<length>12:59</length>
		</thumb>
	</Nicovideo>
	`

	nicoXml := Nicovideo{Thumb{"", ""}}
	err := xml.Unmarshal([]byte(str), &nicoXml)

	if err != nil {
		log.Fatal(err)
		return
	}

	fmt.Println(nicoXml)
	fmt.Println("title: " + nicoXml.Thumb.Title)
	fmt.Println("length: " + nicoXml.Thumb.Length)
}

type Nicovideo struct {
	Thumb Thumb `xml:"thumb"`
}

type Thumb struct {
	Title string `xml:"title"`
	Length string `xml:"length"`
}

いいわけ

構造体のフィールドを大文字始まりで定義するのは、Go言語の仕様で定められているのか、自分の使い方が悪いのかよく分かっていません。