Goで簡単にJSON形式を扱うパッケージ: go-simplejson

More than 3 years have passed since last update.

GoでJSON 形式を扱おうとすると、組み込みのencoding/jsonパッケージでは構造体を使わないとデータにアクセスできないため、pythonライクに簡単なものとして扱いたい自分にとっては多々つらいところがありました。

そこでいろいろ検索してみたところ、同じように考えた人がやはりいるようで以下の二つのパッケージにたどり着くことができました。

go-scanmattn さんが作られたパッケージで、 JSON 形式の読み込みや値の取得を簡単・便利にしてくれます。

一方、 go-simplejsonbitly 社がMITライセンスで公開されているもので、 go-scan に比べると少し手間はかかりますが、 JSON 形式の読み込みや値の取得が簡単に行える他、さらにkeyの追加や削除、変更したデータの[]byte型への変換も可能にしてくれるパッケージです。

この go-simplejson は日本語の記事をほとんど見かけませんでしたが、 JSON に変更を加えることが出来る機能は個人的に有用だと考えたため、その覚書として本記事を残すことにしました。

本記事の内容はgodocを参考に書いており、また自分もGoを触り始めてまだ日も浅いので、挙動を正確に記述していない可能性があります。ご了承ください。


パッケージ取得

パッケージはgo getで取得可能です。

go get github.com/bitly/go-simplejson


使い方

下記のような内容のsample.jsonファイルを対象としたコードです。

{

"hoge": true,
"piyo":{
"foo":[1,2],
"bar":"test"
}
}



package main

import (
"fmt"
"github.com/bitly/go-simplejson"
"io/ioutil"
"log"
"os"
)

func main() {
// ファイルの読み込み
rf, err := ioutil.ReadFile("./sample.json") //[]byte型での読み込み
// r, err := os.Open("./sample.json") //File型での読み込み
if err != nil {
log.Fatal(err)
}

// []byte型からjson型への変換
js, err := simplejson.NewJson(rf)
// []byte型であれば New() を使ってjson型を先んじて作成し、
// UnmarshalJSON() を使って変換することも可能です。
// js := simplejson.New()
// js.UnmarshalJSON(rf)
// File型で読み込んだ場合は下記のように変換できます。
// js, err := simplejson.NewFromReader(r)

// 値の取得
// 各値は Get() や GetPath() とその値の型名と同じ名前の関数を使って取得できます。
// Get() では一つずつkeyを記述するのに対し、 GetPath() では一括して記述することが出来ます。
// また、 Typename() では値とエラーを返し、 MustTypename() では値のみを返します。
b, err := js.Get("hoge").Bool()
m, _ := js.Get("piyo").Map()
a := js.Get("piyo").Get("foo").MustArray()
s := js.GetPath("piyo", "bar").MustString()
fmt.Println(b, m, a, s)

// 値の変更
// Set() や SetPath() を使うことが出来ます。
// SetPath() については下記のkeyの追加、削除の項を参考にしてください。
js.Get("piyo").Set("bar", "test2")
fmt.Println(js.GetPath("piyo", "bar").String())

// keyの追加
// Set() や SetPath() を使うことでkeyの追加も行えます。
// SetPath() では GetPath() と違い、引数に []string{} をとります。
// Set() では直下のkeyしか追加できませんが、SetPath() ではさらに下のkeyも追加できます。
js.Get("piyo").Set("new_hoge", true)
js.SetPath([]string{"piyo", "new_piyo", "new_foo"}, []int{3, 4})
fmt.Println(js.GetPath("piyo", "new_hoge").Bool())
// 本来はArray()で取得したいところなのですが、何故か取得できないためInterface()で無理やり取得しています。
fmt.Println(js.GetPath("piyo", "new_piyo", "new_foo").Interface())

// keyの削除
// Del() を使うことでkeyそのものを削除できます。
js.Get("piyo").Del("new_hoge")
fmt.Println(js.GetPath("piyo", "new_hoge").Bool()) //値の取得に失敗する

// json型から[]byte型への変換
// json型を[]byte型に変換する関数は3つ用意されています。
// MarshalJSON() や Encode() では単純な変換を行い、
// EncodePretty() ではインデントされた状態に変換することが出来ます。
w, err := os.Create("./result.json")
defer w.Close()
// o, _ := js.MarshalJSON()
// o, _ := js.Encode()
o, _ := js.EncodePretty()
w.Write(o)
}


値取得用関数

Typename
説明

Array()
配列

Bool()
論理値

Bytes()
[]byte

Float64()
64bit浮動小数点

Int()
符号付整数

Int64()
64bit符号付整数

Interface()
interface{}

Map()
map

String()
文字列

StringArray()
文字列配列

Uint64()
64bit符号なし整数

これらの関数はすべてその値とエラーの二値を返します。また Bytes()Interface()StringArray() 以外は MustTypename() 関数が存在します。

さらに詳しい内容に関してはGoDocを参照してください。


備考

個人的に GetPath() 関数の引数のとり方が若干使いにくかったので、下記のようにsimplejson.goファイルに、文字列の配列を引数として受け取る GetPathWithArray() を追加しています。

引数のとり方以外は GetPath() 関数と全く同じです。



func (j *Json) GetPathWithArray(branch []string) *Json {
jin := j
for _, p := range branch {
jin = jin.Get(p)
}
return jin
}