JSON をパース(集計/整形など)するときに,よく使われているのは「jq」だと思う.僕も jq をよく使っている(構文は毎回調べるけど).今回は jq 以外の選択肢となる「JMESPath」の理解を深めることにした.JMESPath も JSON をパースできるクエリ言語(仕様)で,例えば AWS CLI の --query
オプションでも採用されている.
JMESPath Tutorial
JMESPath をすぐに試すなら「JMESPath Tutorial」を使うと便利.
よく使う構文を画面上で試すことができるし,実際にクエリを更新するとすぐに反映される.JMESPath Tutorial で試せる構文は以下となる.
- Basic Expressions
- Slicing
- Projections
- List and Slice Projections
- Object Projections
- Flatten Projections
- Filter Projections
- Pipe Expressions
- MultiSelect
- Functions
JMESPath CLI : jp
CLI として使える JMESPath 実装 jp
コマンドもある.良くも悪くも jq
と似すぎ!
今回は brew を使ってインストールしてみた.
$ brew install jmespath/jmespath/jp
$ jp --version
jp version 0.1.3
なお,現在 README.md
に書いてある手順だと異なる jp
が brew からインストールされてしまうため,直接 Formulae を指定する手順に修正するプルリクエストを送った.確実に必要な修正だから merge してもらえると良いんだけど!
基本的な jp
の使い方として,標準出力をパイプして JSON をパースできる.
$ echo '{"key": "value"}' | jp key "value" $ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp foo.bar[1] "b"
既に JSON ファイルがある場合,-f
もしくは --filename
を使うと,ファイルを読み込んで JSON をパースできる.
$ jp --filename input.json foo.bar[1] "b"
jq
を使う場合,よく -r
もしくは --raw-output
を使って,パース結果に "
を付けないようにすると思う.jp
にも同様のオプションがあり,-u
もしくは --unquoted
を使う.また環境変数 JP_UNQUOTED
を使うと,デフォルト設定を変更することもできる.
$ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp --unquoted foo.bar[1] b $ export JP_UNQUOTED=true $ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp foo.bar[1] b
JMESPath Tutorial と jp コマンド
JMESPath Tutorial を一通り試して,気になった構文を jp
コマンドを使って整理しておこうと思う.
Slicing
「Slicing」では,例えば [0:5]
のように書くと,配列データの一部を刈り取ることができる.また [:5]
のように終了のみを指定して刈り取ることもできる.
$ echo '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]' | jp [2:5] [ 2, 3, 4 ] $ echo '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]' | jp [:5] [ 0, 1, 2, 3, 4 ]
Object Projections
「Object Projections」では,例えば ops.*.numArgs
のように中間要素をワイルドカードで指定することができる.
$ echo '{ "ops": { "functionA": {"numArgs": 2}, "functionB": {"numArgs": 3}, "functionC": {"variadic": true} } }' | jp ops.*.numArgs [ 2, 3 ]
Filter Projections
「Filter Projections」では,例えば machines[?state=='running'].name
のように要素に対して条件を書くことができる.
$ echo '{ "machines": [ {"name": "a", "state": "running"}, {"name": "b", "state": "stopped"}, {"name": "b", "state": "running"} ] }' | jp "machines[?state=='running'].name" [ "a", "b" ]
Functions
「Functions」では,例えば length(people)
など,ビルトイン関数を使って集計することもできる.他にも max
や merge
など,多く用意されている.
$ echo '{ "people": [ { "name": "b", "age": 30, "state": {"name": "up"} }, { "name": "a", "age": 50, "state": {"name": "down"} }, { "name": "c", "age": 40, "state": {"name": "up"} } ] }' | jp "length(people)" 3
JMESPath Specification
JMESPath の全仕様は「JMESPath Specification」に載っている.ビルトイン関数の一覧も確認できる.
言語別 JMESPath 実装
多くの言語に JMESPath 実装がある.バックエンド実装で JSON をパースする場面があれば検討しても良さそう.
- Python
- PHP
- JavaScript
- Ruby
- Lua
- Go
- Java
- Rust
- .NET
まとめ
- JSON をパース(集計/整形など)するときに「jq」以外の選択肢となる「JMESPath」を試した
- JMESPath をすぐに試すなら「JMESPath Tutorial」を使うと便利
- JMESPath CLI として使える
jp
コマンドもある - (慣れの問題もあるけど)個人的には「jq」よりも「JMESPath」の方が構文の可読性が高いように感じた