LoginSignup
26

More than 5 years have passed since last update.

Go言語でのJSONデータの扱い【備忘録】

Last updated at Posted at 2017-06-14

JSONの処理

JSONを扱う場合encoding/jsonを使う。Goの場合、JSONデータを定義した構造体に入れるのが一般的。

JSONの解析

{
    "id": 1,
    "name": "nana",
    "birthday": "08-16",
    "vivid_info": {
      "color": "red",
      "weapon": "Rang"
    }
}

このようなデータ構造の場合、以下のように構造体を定義する。

type Person struct {
    ID int `json:"id"`
    Name string `json:"name"`
    Birthday string `json:"birthday"`
    VividInfo struct {
        Color string `json:"color"`
        Weapon string `json:"weapon"`
    } `json:"vivid_info"`
}

JSONから構造体のコードを生成してくれるJSON-to-Goを使うと便利。

JSONをデコードするにはjson.Unmarshal関数を使う。

func Unmarshal(data []byte, v interface{}) error

デコードされたデータは以下のようにして扱うことができる。

var persons []Person
for _, p := range persons{
  fmt.Printf("%d : %s : %s : %s : %s\n", p.ID, p.Name, p.Birthday, p.VividInfo.Color, p.VividInfo.Weapon)
}

// 表示結果
// 1 : nana : 08-16 : red : Rang

未知のデータ構造をもつJSONの解析

JSONデータの構造を事前に知らない場合、interfaceを用いて解析する。JSONパッケージではmap[string]interface{}interface{}構造を採用して任意のJSONオブジェクトを保存する。Goの型とJSONの型の対応は以下。

  • boolはJSON booleansを表す。
  • float64はJSON numberを表す。
  • stringはJSON stringを表す。
  • nilはJSON nilを表す。

以下のようなJSONデータがあるとし、この構造を把握していないと仮定する。

b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)

これをinterface{}の中に解析。

var f interface{}
err := json.Unmarshal(b,&f)

このときfの中にはmap型が保存されている。これらのkeyはstringで、値は空のinterface{}の中に保存される。

f = map[string]interface{}{
  "Name": "Wednesday",
    "Age":  6,
    "Parents": []interface{}{
        "Gomez",
        "Morticia",
    },
}

これらのデータにアクセスするには以下のようにする。

m := f.(map[string]interface{})
for k, v := range m {
  switch vv := v.(type) {
  case string:
    fmt.Println(k, "is string", vv)
  case int:
    fmt.Println(k, "is int", vv)
  case float64:
    fmt.Println(k, "is float64", vv)
  case []interface{}:
    fmt.Println(k, "is an array:")
    for i, u := range vv {
      fmt.Println(i, u)
    }
  default:
    fmt.Println(k, "is of a type I dont know how to handle")
  }
}

(めんどくさいのでJSONを取得してJSON-to-Goを利用して構造体にぶち込んだほうが見通しが良さそう。)

go-simplejson

上の例よりも簡単にJSONを扱うことのできるパッケージ

go get github.com/bitly/go-simplejson

使い方

下記のjsonを扱う場合、

[simple.json]
{
    "hoge": true,
    "piyo":{
        "foo":[1,2],
        "bar":"test"
    }
}
import( 
  simplejson "go-simplejson"
)

//jsonファイルの読み込み
bytes, err := ioutil.ReadFile("./simple.json")
if err != nil {
  log.Fatal(err)
}

// []byte型からjson型へ変換
json,err := simplejson.NewJson(bytes)

// Get("hoge").Type()またはGet("hoge").MustType()でアクセスできる。
// Type()は値とエラーを返す
b, _ := json.Get("hoge").Bool() // => true
 // MustType()は値のみ
m := json.Get("piyo").MustMap() // => map[bar:test foo:[1 2]]
a, _ := json.Get("piyo").Get("foo").Array()  // => [1,2]
// GetPath()で一括記述
s := js.GetPath("piyo", "bar").MustString() // => test

以下のような、配列で構成されるJSONデータの扱いは

[
  {
    "id": 1,
    "name": "akane",
    "birthday": "08-16",
    "vivid_info": {
      "color": "red",
      "weapon": "Rang"
    }
  },
  {
    "id": 2,
    "name": "aoi",
    "birthday": "06-17",
    "vivid_info": {
      "color": "blue",
      "weapon": "Impact"
    }
  },
  {
    "id": 3,
    "name": "wakaba",
    "birthday": "05-22",
    "vivid_info": {
      "color": "green",
      "weapon": "Blade"
    }
  },
  {
    "id": 4,
    "name": "himawari",
    "birthday": "07-23",
    "vivid_info": {
      "color": "yellow",
      "weapon": "Collider"
    }
  },
  {
    "id": 0,
    "name": "rei"
  }
]

このようにforで回してアクセス。他にもっといい方法あったら教えてください。

for i, _ := range json.MustArray() {
  fmt.Printf("id: %d\n", json.GetIndex(i).Get("id").MustInt())
  fmt.Printf("name: %s\n", json.GetIndex(i).Get("name").MustString())
  fmt.Printf("birthday: %s\n", json.GetIndex(i).Get("birthday").MustString())
  fmt.Printf("vivid_info:color: %s\n", json.GetIndex(i).Get("vivi_info").Get("color").MustString())
  fmt.Printf("vivid_info:weapon: %s\n", json.GetIndex(i).Get("vivi_info").Get("weapon").MustString())
}

rubyに比べると少し面倒な印象。

参考

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26