LoginSignup
4
4

More than 5 years have passed since last update.

golangでjsonを編集するの作ったver2

Last updated at Posted at 2017-03-13

URL

以前作ったfilebase
http://qiita.com/intelf___/items/b630020e4619b19d1d48

改良版 jsonbase(Github)
https://github.com/intelfike/jsonbase

破壊的な変更とともに名前ごと変えてみました。
分かりやすくなったはず。

リンク先の見方

setter.go => 値を変更、追加、削除できるメソッド群
getter.go => 値を取得、型変換できるメソッド群
checker.go => 値の型チェック、存在の確認などできるメソッド群
referer.go => 値の子、親要素の移動をして参照するためのメソッド群
(自作ツールのlffの結果をそのまま載せています)

できること

・jsonのデータの取り出し、型変換 (Interface/To??)
・jsonのデータの編集 (Set/Push)
・jsonデータの生成 (Set/Push)
・jsonのデータの削除 (Remove/Empty)
・jsonのデータの読み取り、書き出し (WriteTo/Reader)
・gzipファイル(拡張子.gz)対応 (WriteToFile/ReadFile)

変更点

初期化

filebase(旧)

fb, err := filebase.New(`{"key":"value"}`)
if err != nil{
 // panic回避
}
fmt.Println(fb)

jsonbase(新)

jb := jsonbase.New()
jb.Set().JsonText(`{"key":"value"}`)
fmt.Println(jb)

New系でできてたjsonの生成を全てSet/Pushに移行しました。

Set/Push

filebase(旧)

fb, err := filebase.New(`{}`)
if err != nil{
 // panic回避
}
fb.Child("key").Set("value")
fmt.Println(fb)

jsonbase(新)

jb := jsonbase.New()
jb.Child("key").Set().Value("value")
fmt.Println(jb)

Set/Push系が少しだけ文字数が増えました。
一度引数なしのSet/Pushを呼び出して、次に値の書き出し方、その引数に値を指定する形です。
これによりSet/Pushを同様に扱えるようになりました。

また、nil参照によるpanicも起きないようになっています。
(set失敗時にはちゃんとValueメソッドからerrorを取得できます。)

配列へのアクセス

jb.ChildPath("1/key")

このように文字列として数字を書いた時に、jsonのノードがArrayであれば自動的に数値として認識してくれるようになりました。

主な変更点はこれくらいです。

Set/Pushの違い

旧バージョンと同様です。

jb = jsonbase.New()
jb.Set().Value(1)
jb.Set().Value(2)

出力

2

Setではこのように最新の値に更新されます。

jb := jsonbase.New()
jb.Push().Value(1)
jb.Push().Value(2)
fmt.Println(jb)

出力

[1,2]

PushではArrayが生成されて、値が追加されます。
過去の値が消えません。

巨大な入れ子

jb := jsonbase.New()
// 30回入れ子
for n := 0; n < 30; n++ {
    jb = jb.ChildPathf("%d=%05b", n, n)
}
jb.Set().Printf(`"=====%d====="`, 1<<30)// 実際に値をセット
fmt.Println(jb.Ancestor(7)) // 7回親を辿って表示

出力

{"23":{"24":{"25":{"26":{"27":{"28":{"29":"=====1073741824====="}}}}}}}

Childで参照した先も元の構造体と同じ型なので、このように代入することができます。

ファイルパスをjsonに変換したい

fdlist := []string{
    "./main.go",
    "./lib/module.go",
    "./lib/reg.go",
    "./empty/",
}
jb := jsonbase.New()
jb.Indent = "  "
for _, v := range fdlist {
    d, f := filepath.Split(v)       // ディレクトリ・ファイルの分割
    d = strings.Trim(d, "/")        // 余分なスラッシュを削除
    jb.ChildPath(d).Push().Value(f) // 追加
}
fmt.Println(jb)

出力

{
  ".": {
    "empty": [
      ""
    ],
    "lib": [
      "module.go",
      "reg.go"
    ]
  }
}

panicを回避したい

設計上panicはほとんど発生しません。
ToBool()などで変換できない型を指定するなどでpanic()が発生します。
ですが、これらはchecker.goのメソッド(冒頭URL参照)で回避できます。

jb := jsonbase.New() // 初期値なのでnull
if jb.IsBool(){ // 値がboolに変換できるかチェック
  fmt.Println(jb.ToBool()) // 実行されない
}

出力なし

テンプレートを使いたい

テンプレートを作るためのメソッドとして、参照を切り離すClone()や、参照を切り離して値をセットするJB()があります。
毎回パースしないので一見軽そうですが、実際は参照を切り離す処理が入るのでほとんど変わりません(むしろ遅い?)。

jb := jsonbase.New()
jb.Indent = "  "
template := jsonbase.New()
template.Set().JsonText(`{"key":"value", "id":0}`)
for n := 0; n < 3; n++ {
    jb.Child("top").Push().JB(template)         // テンプレートを追加
    jb.Child("top", n, "id").Set().Value(n + 1) // 新しく追加したテンプレートのidを書き換え}
}
fmt.Println(jb)
}

出力

{
  "top": [
    {
      "id": 1,
      "key": "value"
    },
    {
      "id": 2,
      "key": "value"
    },
    {
      "id": 3,
      "key": "value"
    }
  ]
}

実装例

lffコマンドの-jsonオプションに使いました。
条件分岐も含めて大体20行くらいで実装出来たので、かなり便利でした。

管理

個人で管理しているので、こうしたほうが良い、こんな不具合があるなどお知らせ頂ければ直ちに修正、コミットできます。
逆に、簡単に破壊的変更が簡単にできちゃう。けど、go getでは更新されないから多分大丈夫。

あと、開発者が日本人なので質問なども日本語で気軽に出来るという利点が。
twitterアカウントはこちら。
@intelfike

変更管理

(公開時ver1.0)
https://github.com/intelfike/jsonbase/blob/master/change_history.txt

4
4
0

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
4
4