brew install jq しましょう。まずはそれからだ。
** JSON の整形
良くあるけど、どっかの API から雑なかんじで適当にインデントされた JSON が返却されたりして、JSONPath を書くにしろ、まずは整形しないと JSON の構造が分からん、みたいな悲しいことになって人類が不幸になる。
たとえばこんな JSON があるとして、見た瞬間ウッてなって開発者が一人不幸になる。
|tcsh| $ cat sample.json {"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }} ||< でも、jq があればもう安心、sample.json の整形がコマンドラインからできます。 |tcsh| $ jq . sample.json { "menu": { "popup": { "menuitem": [ { "onclick": "CreateNewDoc()", "value": "New" }, { "onclick": "OpenDoc()", "value": "Open" }, { "onclick": "CloseDoc()", "value": "Close" } ] }, "value": "File", "id": "file" } } ||< こんな pretty-print された JSON なんて冗長すぎてクソつまらん、おれは効率重視だ、みたいな多様な要望を抱える人間のために、-c (--compact-output) なんてのもあってバイト数が良い感じになる。個人的にはウッてなるけど、多様な価値観を認めるのが人間社会の美徳です。 |tcsh| $ jq -c . sample.json {"menu":{"popup":{"menuitem":[{"onclick":"CreateNewDoc()","value":"New"},{"onclick":"OpenDoc()","value":"Open"},{"onclick":"CloseDoc()","value":"Close"}]},"value":"File","id":"file"}} ||<
**フィルタ
で、ここからがフィルタ。 jq ではフィルタを書くことができて、XPath みたいな感じで特定要素を取得できたりする。たぶん、説明するよりか見た方がはやい。
|tcsh| $ jq ".menu.popup.menuitem" sample.json
{ "onclick": "CreateNewDoc()", "value": "New" }, { "onclick": "OpenDoc()", "value": "Open" }, { "onclick": "CloseDoc()", "value": "Close" } ] ||< このように、ルートから階層を辿るようにフィルタを書けば、その部分の要素が出力できる。いいかんじですね。 *** 配列要素の一部のみ抽出 上記の要素は配列ですけど、2 番目と 3 番目の要素を抽出しようと思ったらこんなかんじ。
|tcsh| $ jq ".menu.popup.menuitem[1,2]" sample.json { "onclick": "OpenDoc()", "value": "Open" } { "onclick": "CloseDoc()", "value": "Close" } ||< *** 配列の全要素を抽出 [1,2,3] とか全要素について書いていくのダルいから、いっそのこと何も書かなかったら全要素が抽出されて幸せが芽生える。 |tcsh| $ jq ".menu.popup.menuitem" sample.json { "onclick": "CreateNewDoc()", "value": "New" } { "onclick": "OpenDoc()", "value": "Open" } { "onclick": "CloseDoc()", "value": "Close" } ||<
***フィルタの組み合わせ
フィルタをパイプでつなげるみたいなこともできます。 1 プロセスでできるから「シェルのパイプは複数プロセス立ち上げるからリソースが云々」みたいなことを言うリソースお化けもイチコロだ。
|tcsh| $ jq ".menu.popup.menuitem | .onclick" sample.json "CreateNewDoc()" "OpenDoc()" "CloseDoc()" ||<
こっちのフィルタとこっちのフィルタ、両方とも通して、出力はマージしたいみたいなときあるけど、奥さん、それも jq でできます。
|tcsh| $ jq ".menu.popup.menuitem[] | .value, .onclick " sample.json "New" "CreateNewDoc()" "Open" "OpenDoc()" "Close" "CloseDoc()" ||< いろいろあるけど、応用編に続きます。