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でのオプションをさらっと見ていく
に書かれている。
例)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"
]
}
それ以外にも関数はあるけど、書いてて時間が足りないので
必要になったら使ってみよう