go でjson をパースする(構造体あり、なしパターン)
はじめに
go でjson をパースする方法をまとめます。
構造体を使うパターンとbuger/jsonparser を利用して構造体を使わないパターンを書きます。
go でjson をパースする
個人的には構造体を書けばいいと思ってますが、めんどくさいなぁと思うこともあるかもしれません。ないかもしれません。ないですね。書きましょう。
今回利用するjson はこんな感じです。
{ "person": { "name": { "first": "Leonid", "last": "Bugaev", "fullName": "Leonid Bugaev" }, "github": { "handle": "buger", "followers": 109 }, "avatars": [ { "url": "https://avatars1.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" }, { "url": "https://avatars1.githubusercontent.com/u/14010?v=2&s=460", "type": "thumbnail" } ] }, "company": { "name": "Acme" } }
構造体の生成といえばここですね。
構造体を使ってjson をパースする
構造体を使ってjson をパースします。
ちなみに例えば外部サービスのAPIで予期せず項目が追加になるかもしれなくて不安。みたいなお話がありますが、増える分にはエラーにもなりません。
package main import ( "encoding/json" "fmt" "log" ) type Employee struct { Person struct { Name struct { First string `json:"first"` Last string `json:"last"` FullName string `json:"fullName"` } `json:"name"` Github struct { Handle string `json:"handle"` Followers int `json:"followers"` } `json:"github"` Avatars []struct { URL string `json:"url"` Type string `json:"type"` } `json:"avatars"` } `json:"person"` // Company struct { // Name string `json:"name"` // } `json:"company"` } func main() { data := []byte(`{ "person": { "name": { "first": "Leonid", "last": "Bugaev", "fullName": "Leonid Bugaev" }, "github": { "handle": "buger", "followers": 109 }, "avatars": [ { "url": "https://avatars1.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" }, { "url": "https://avatars1.githubusercontent.com/u/14010?v=2&s=460", "type": "thumbnail" } ] }, "company": { "name": "Acme" } }`) // Use struct var employee Employee if err := json.Unmarshal(data, &employee); err != nil { log.Fatal(err) } fmt.Printf("Employee Person FullName: %s\n", employee.Person.Name.FullName) for _, a := range employee.Person.Avatars { fmt.Printf("Employee Person Avatars: %s, %s\n", a.URL, a.Type) } }
$ go run jsonparser.go Employee Person FullName: Leonid Bugaev Employee Person Avatars: https://avatars1.githubusercontent.com/u/14009?v=3&s=460, thumbnail Employee Person Avatars: https://avatars1.githubusercontent.com/u/14010?v=2&s=460, thumbnail
構造体を使わずjson をパースする
構造体を使わずにjson をパースします。
buger/jsonparser を利用します。
package main import ( "fmt" "log" "github.com/buger/jsonparser" ) func main() { data := []byte(`{ "person": { "name": { "first": "Leonid", "last": "Bugaev", "fullName": "Leonid Bugaev" }, "github": { "handle": "buger", "followers": 109 }, "avatars": [ { "url": "https://avatars1.githubusercontent.com/u/14009?v=3&s=460", "type": "thumbnail" }, { "url": "https://avatars1.githubusercontent.com/u/14010?v=2&s=460", "type": "thumbnail" } ] }, "company": { "name": "Acme" } }`) // Not use struct value, _, _, err := jsonparser.Get(data, "person", "name", "fullName") if err != nil { log.Fatal(err) } fmt.Printf("Employee Person FullName: %s\n", string(value)) _, err = jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { url, _, _, err := jsonparser.Get(value, "url") if err != nil { log.Fatal(err) } urlType, _, _, err := jsonparser.Get(value, "type") if err != nil { log.Fatal(err) } fmt.Printf("Employee Person Avatars: %s, %s\n", string(url), string(urlType)) }, "person", "avatars") if err != nil { log.Fatal(err) } }
配列内の要素へのアクセスが少し手間ですが構造体なしにここまでできるのはすごいですね。
$ go run jsonparser.go Employee Person FullName: Leonid Bugaev Employee Person Avatars: https://avatars1.githubusercontent.com/u/14009?v=3&s=460, thumbnail Employee Person Avatars: https://avatars1.githubusercontent.com/u/14010?v=2&s=460, thumbnail
まとめ
go でjson をパースする方法をまとめました。
技術書展に行って私の中のgo熱の高まりを感じます。