Edited at

【個人メモ】JSONのパースにjmespathを使ってみよう

More than 3 years have passed since last update.


jmespath

JSONのパースには、jqというツールが有名である。

が、昨日、aws-cliにて、--query オプションにより

jmespath形式でのJSONパースを利用できる、ということで

jmespathそのものを試してみることにした。


jmespathをインストール

pipでインストールできる。

> pip install —user jmespath

インストール後、コマンドラインツールとしてjpコマンドを実行することが可能になる

> echo '{"a": "100"}' | jp a

“100"

簡単だ。

aws-cliでの出力を例に取りながら、

jmespathでのオプションをさらっと見ていく

JMESPath Tutorial

に書かれている。


例)aws-cliを利用してec2 instanceのprivate ipアドレスのみを取得してみる

管理している同立しているサービス向けのインスタンスの台数が30台〜とかなると

IPアドレスを抜くにも一苦労だったりする。


aws-cliでtext出力を行い、cutに食わせて出させる場合

aws ec2 describe-instances --filter "Name=tag:Role,Values=web-front" --output text | grep PRIVATEIPADDRESSES | cut -f3

10.0.1.1
10.0.1.2
10.0.1.3
10.0.1.4
10.0.1.5
...
10.0.1.50

こんな感じになってしまう。


jmespathを利用してaws-cliのJSON出力をパースするようにする

aws ec2 describe-instances --filter "Name=tag:Role,Values=web-front" --query "Reservations[*].Instances[*].PrivateIpAddress[]”

[
“10.0.1.1”,
“10.0.1.2”,
“10.0.1.3”,
“10.0.1.4”,
“10.0.1.5”,

“10.0.1.50”
]


便利組み込み関数を利用してみる

aws cliがjmespathのクエリパスをサポートしているのは確認できた。

その他、jmespathに組み込まれているsearch関数を利用してみよう


search関数

search関数は表現力が高い。

Hashのキーマッチングやフィルタリングに対応している。


たとえば

以下のJSONデータがあるとする

[

{
"name": "Keiji Matsuzaki",
"age": 33,
"language":
[
"Japanese"
],
"programming": {
"language":
[
"PHP",
"Python",
"Go",
"Ruby"
]
}
},
{
"name": "Fujisan Taro",
"age": 24,
"language":
[
"Japanese"
],
"programming": {
"language":
[
"Rust",
"C++",
"Erlang",
"Go"
]
}
},
{
"name": "Lim Chow",
"age": 28,
"language":
[
"English",
"Chinese"
],
"programming": {
"language":
[
"Ruby",
"sass",
"Lua",
"C"
]
}
},
{
"name": "Jem Tomas",
"age": 52,
"language":
[
"English",
"French"
],
"programming": {
"language":
[
"C",
"BASIC",
"NASM",
"HTML",
"Go",
"Haskell"
]
}
}
]

ここから、以下の条件に合致するデータを取り出す


language: englishが含まれているレコードはどれぐらいあるか

jmespathでパースする場合はこうなる

jp -f test.json 'length([].language[?@==`English`][])'

> 2


どういうことか

[].language[] で、languageの要素を取得する。

[

[
"Japanese"
],
[
"Japanese"
],
[
"English",
"Chinese"
],
[
"English",
"French"
]
]


language[]のものから、current node == Englishに合致するものを検索する

[].language[?@==English]

[

[],
[],
[
"English"
],
[
"English"
]
]


arrayごとに分割されているのでflatten化する

[].language[?@==English][]

[

"English",
"English"
]


length関数により、要素数を数える

length([].language[?@==English][])

> 2

なお、jpコマンドはデフォルトでsearch関数を利用するようになっている。

jp#43



年齢の平均

jp -f test.json 'avg([].age)’

> 34.25


年齢が一番高い人

jp -f test.json 'max_by([], &age)’

{

"age": 52,
"programming": {
"language": [
"C",
"BASIC",
"NASM",
"HTML",
"Go",
"Haskell"
]
},
"name": "Jem Tomas",
"language": [
"English",
"French"
]
}

それ以外にも関数はあるけど、書いてて時間が足りないので

必要になったら使ってみよう

jmespathで利用できる関数一覧