Go言語(golang) YAMLの使い方
golangにはYAMLの標準パーッケージはありません。
なので yaml.v2 を使って、
YAML から go言語のデータ型(構造体やマップなど) に変換(Unmarshal,Decode) と、
その逆で go言語のデータ型から YAML に変換(Marshal,Encode) します。
以下、パッケージのダウンロード、Unmarshal,Decode,Marshal,Encode それぞれの使い方、
構造体のタグ(アノテーション) についてサンプルコードで説明しています。
※データを読み込むだけなら yaml,json 形式どちらも扱えます。
YAML 公式ページ
ライブラリ yaml.v2
ソース: go-yaml/yaml GitHub
ドキュメント: yaml.v2 godoc
目次
ダウンロード - download
$ go get gopkg.in/yaml.v2
使い方
YAML から map にする - Unmarshal
package main import ( "fmt" "log" "os" yaml "gopkg.in/yaml.v2" ) func main() { var m map[string]interface{} data := ` name: Tanaka age: 30 ` // JSONでも同じで、ポインタで渡す err := yaml.Unmarshal([]byte(data), &m) if err != nil { log.Fatal(err) } fmt.Printf("%v\n", m) // map[name:Tanaka age:30] }
YAML から構造体にする - UnmarshalStrict
厳格モード。キーの重複や、構造体にフィールド名が無い場合にエラーになる
package main import ( "fmt" "log" yaml "gopkg.in/yaml.v2" ) type Profile struct { Name string `yaml:"name"` Age int `yaml:"age"` } func main() { data := ` name: Tanaka age: 31 ` var p Profile err := yaml.UnmarshalStrict([]byte(data), &p) if err != nil { log.Fatal(err) } fmt.Printf("%#v\n", p) // main.Profile{Name:"Tanaka", Age:31} // 以下は厳格モードなのでエラー // name が重複でエラーになる // line 3: field name already set in type main.Profile // unknown は Profile のフィールド名にないのでエラー // line 4: field unknown not found in type main.Profile data = ` name: Tanaka name: Suzuki unknown: 1000 ` err = yaml.UnmarshalStrict([]byte(data), &p) if err != nil { log.Fatal(err) } }
map から YAML([]byte) に変換 - Marshal
Go言語のデータ型(struct,map,slice)から YAML に変換する
package main import ( "fmt" "log" "os" yaml "gopkg.in/yaml.v2" ) func main() { m := map[string]interface{}{ "name": "Tanaka", "age": 30, } data, err := yaml.Marshal(m) if err != nil { log.Fatal(err) } fmt.Println(string(data)) // age: 30 // name: Tanaka }
デコード - NewDecoder - Decode
YAML データから Go のデータ型(map,slice,struct) に変換する
package main import ( "fmt" "log" "os" "strings" yaml "gopkg.in/yaml.v2" ) func main() { var m map[string]interface{} data := ` name: Tanaka age: 30 ` d := yaml.NewDecoder(strings.NewReader(data)) // UnmarshalStrict と同じで厳格モードにするなら以下を指定する // デフォルトは、厳格モードは無効 // 当然ですが、 d.Decode(&m) の前に指定する必要がある d.SetStrict(true) err := d.Decode(&m) if err != nil { log.Fatal(err) } fmt.Printf("%v\n", m) // map[name:Tanaka age:30] }
ファイルから読み込む
package main import ( "fmt" "log" "os" yaml "gopkg.in/yaml.v2" ) func main() { f, err := os.Open("hello.yml") if err != nil { log.Fatal(err) } defer f.Close() d := yaml.NewDecoder(f) var m map[string]interface{} if err := d.Decode(&m); err != nil { log.Fatal(err) } fmt.Printf("%v\n", m) // map[name:Tanaka age:30] }
エンコード - NewEncoder - Encode
Goのデータ型(map,slice,struct) などから、YAML に変換して書き込む
package main import ( "bytes" "fmt" "log" yaml "gopkg.in/yaml.v2" ) func main() { data := map[string]interface{}{"name": "Tanaka", "age": 31} var b bytes.Buffer d := yaml.NewEncoder(&b) err := d.Encode(&data) if err != nil { log.Fatal(err) } d.Close() // 残りのデータを書き込んでエンコーダを終了する fmt.Printf("%s\n", b.String()) // name: Tanaka // age: 30 }
ファイルに書き込む
package main import ( "log" "os" yaml "gopkg.in/yaml.v2" ) func main() { data := map[string]interface{}{"name": "Tanaka", "age": 31} f, err := os.OpenFile("hello.yml", os.O_WRONLY|os.O_CREATE, 0664) if err != nil { log.Fatal(err) } defer f.Close() d := yaml.NewEncoder(f) if err := d.Encode(&data); err != nil { log.Fatal(err) } d.Close() }
構造体のタグ - tags
タグの指定方法
yaml:"[名前][,オプション1[,オプション2]]"
オプション
- omitempty
構造体の値が初期値だった場合は、YAMLとして出力されない
初期値とは string型 なら 空文字、int型 なら 0 など
- flow
YAML のフロースタイルで出力する
フロースタイルとは JSON のような形式(デフォルトはブロックスタイル){ name: Tanaka, age: 30 }
- inline
構造体またはマップに使うことができる
- "-"
タグの名前に yaml:"-" を指定した場合は、そのフィールドは無視される
名前を指定しても Name string `yaml:"name"`
は Name でも name でもどちらでもよい。
構造体のフィールド名が小文字 name string `yaml:"name"`
の場合は、"-" 同様で無視される。
inline,flow を指定した場合と指定しない場合
package main import ( "fmt" "log" yaml "gopkg.in/yaml.v2" ) func main() { { // オプションの指定なし u := struct { Name string `yaml:"name"` Age int `yaml:"age"` Score map[string]int `yaml:"score"` }{ Name: "Tanaka", Age: 30, Score: map[string]int{"1st": 10, "2nd": 20, "3rd": 30}, } data, err := yaml.Marshal(u) if err != nil { log.Fatal(err) } fmt.Println(string(data)) // name: Tanaka // age: 30 // score: // 1st: 10 // 2nd: 20 // 3rd: 30 } { // inline を指定 u := struct { Name string Age int Score map[string]int `yaml:"score,inline"` }{ Name: "Tanaka", Age: 30, Score: map[string]int{"1st": 10, "2nd": 20, "3rd": 30}, } data, err := yaml.Marshal(u) if err != nil { log.Fatal(err) } fmt.Println(string(data)) // name: Tanaka // age: 30 // 1st: 10 // 2nd: 20 // 3rd: 30 } { // flow を指定 u := struct { Name string Age int Score map[string]int `yaml:"score,flow"` }{ Name: "Tanaka", Age: 30, Score: map[string]int{"1st": 10, "2nd": 20, "3rd": 30}, } data, err := yaml.Marshal(u) if err != nil { log.Fatal(err) } fmt.Println(string(data)) // name: Tanaka // age: 30 // score: {1st: 10, 2nd: 20, 3rd: 30} } }