JSONPathは、JSONデータから特定の値を抽出するためのクエリ言語です。XPathのJSON版だと思ってもらえればOK。REST APIのレスポンスから必要なフィールドだけ取り出したり、巨大なJSONの中から条件に合うデータを探したり——そんな場面で重宝します。
この記事では、基本構文からフィルター式まで、実際に手を動かしながら覚えられるように紹介していきます。
サンプルデータ
まずは、この記事で使うサンプルデータを用意しましょう。よくある書店APIのレスポンスです。
{ "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], "bicycle": { "color": "red", "price": 399.99 } }}基本構文
JSONPathの構文は $ から始まります。これがJSONのルート要素を指します。
ドット記法
ドット(.)でプロパティにアクセスできます。JavaScriptのオブジェクトアクセスと同じ感覚です。
$.store.bicycle.color→ "red"
$.store.bicycle.price→ 399.99ブラケット記法
ブラケット([])でもプロパティにアクセスできます。プロパティ名にドットやスペースが入っているときはこっちを使います。
$.store['bicycle']['color']→ "red"
$['store']['book'][0]['title']→ "Sayings of the Century"配列へのアクセス
配列はインデックス(0始まり)で要素を取り出せます。
$.store.book[0]→ { "category": "reference", "author": "Nigel Rees", ... }
$.store.book[0].author→ "Nigel Rees"
$.store.book[3].title→ "The Lord of the Rings"ワイルドカード
* はワイルドカードで、配列の全要素やオブジェクトの全プロパティにマッチします。
$.store.book[*].title→ ["Sayings of the Century", "Sword of Honour", "Moby Dick", "The Lord of the Rings"]
$.store.book[*].author→ ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"]
$.store.*→ [book配列全体, bicycle オブジェクト]全書籍のタイトルをまとめて取得できるのは便利ですよね。
再帰検索(ディープスキャン)
.. を使うと、ネストの深さに関係なく、指定したキーを持つ値をすべて探してくれます。
$..price→ [8.95, 12.99, 8.99, 22.99, 399.99]
$..author→ ["Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"]
$..isbn→ ["0-553-21311-3", "0-395-19395-8"]$..price は store.book[*].price と store.bicycle.price の両方にマッチします。データ構造をよく知らなくても、とりあえず .. で探せるのが強みです。
配列スライス
Pythonのスライスと同じ感覚で、配列の一部を取り出せます。
構文
[start:end] startからend-1まで[start:] startから末尾まで[:end] 先頭からend-1まで[-n:] 末尾からn個[start:end:step] stepごとに取得使用例
$.store.book[0:2]→ [最初の2冊(インデックス0と1)]
$.store.book[-1]→ { "category": "fiction", "author": "J. R. R. Tolkien", ... }
$.store.book[-2:]→ [最後の2冊(Moby Dick, The Lord of the Rings)]
$.store.book[::2]→ [インデックス0と2の書籍(1つおき)]負のインデックスを使うと末尾から数えられます。[-1] で最後の要素、[-2:] で最後の2つを取得。
フィルター式
ここからがJSONPathの真骨頂です。?() を使うと、条件に合う要素だけを抽出できます。@ が「今見ている要素」を指します。
比較演算子
$.store.book[?(@.price < 10)]→ [price が 10 未満の書籍(Sayings of the Century, Moby Dick)]
$.store.book[?(@.price > 20)]→ [price が 20 を超える書籍(The Lord of the Rings)]
$.store.book[?(@.category == 'fiction')]→ [category が "fiction" の書籍(3冊)]存在チェック
$.store.book[?(@.isbn)]→ [isbn プロパティを持つ書籍(Moby Dick, The Lord of the Rings)]isbn フィールドは一部の書籍にしかありません。?(@.isbn) で「そのフィールドを持つ要素」だけ取り出せるわけです。
論理演算子
条件を組み合わせることもできます。
$.store.book[?(@.price < 10 && @.category == 'fiction')]→ [price が 10 未満かつ fiction の書籍(Moby Dick)]
$.store.book[?(@.price < 10 || @.price > 20)]→ [price が 10 未満または 20 を超える書籍]実践例:APIレスポンスからデータを抜き出す
実際のAPIレスポンスを想定した例を見てみましょう。
ユーザー一覧APIから欲しいデータだけ取る
{ "status": "ok", "data": { "users": [ { "id": 1, "name": "Alice", "role": "admin", "active": true }, { "id": 2, "name": "Bob", "role": "editor", "active": true }, { "id": 3, "name": "Charlie", "role": "viewer", "active": false }, { "id": 4, "name": "Diana", "role": "admin", "active": true } ], "total": 4 }}# 全ユーザーの名前$.data.users[*].name→ ["Alice", "Bob", "Charlie", "Diana"]
# アクティブなユーザーのみ$.data.users[?(@.active == true)].name→ ["Alice", "Bob", "Diana"]
# 管理者だけを取得$.data.users[?(@.role == 'admin')]→ [Alice, Diana のオブジェクト]
# アクティブな管理者の名前$.data.users[?(@.role == 'admin' && @.active == true)].name→ ["Alice", "Diana"]ネストが深いレスポンスもOK
{ "orders": [ { "id": "ORD-001", "items": [ { "product": "Laptop", "price": 999, "qty": 1 }, { "product": "Mouse", "price": 29, "qty": 2 } ] }, { "id": "ORD-002", "items": [ { "product": "Keyboard", "price": 79, "qty": 1 } ] } ]}# 全注文の全商品名$..product→ ["Laptop", "Mouse", "Keyboard"]
# 100ドル以上の商品$.orders[*].items[?(@.price >= 100)]→ [{ "product": "Laptop", "price": 999, "qty": 1 }]当サイトのツールで試す
当サイトの JSONフォーマッター にはJSONPath検索機能がついています。この記事のサンプルデータを貼り付けて、いろいろクエリを試してみてください。
- JSONフォーマッターにJSONデータを貼り付ける
- JSONPath入力欄にクエリを入れる(例:
$.store.book[*].title) - マッチした結果が表示される
やっぱり手を動かすのが一番覚えが早いです。
まとめ
JSONPathの主要な構文をおさらいします。
| 構文 | 説明 | 例 |
|---|---|---|
$ | ルート要素 | $ |
.key | プロパティアクセス | $.store.book |
['key'] | ブラケットアクセス | $['store']['book'] |
[n] | 配列インデックス | $.store.book[0] |
[*] | ワイルドカード | $.store.book[*] |
.. | 再帰検索 | $..price |
[start:end] | スライス | $.store.book[0:2] |
?() | フィルター | $[?(@.price < 10)] |
@ | 現在の要素 | ?(@.active == true) |
JSONPathを使えば、複雑なJSONからサクッと必要なデータを抜き出せます。APIレスポンスの確認やデータ探索に、ぜひ使ってみてください。
JSONPathってXPathのJSON版なんだね!$..price みたいにドットを2つ並べるだけで、どんなに深い階層にあるデータでも一発で見つけられるのがすごい。JSONフォーマッターで実際に試してみると、クエリの動きが目に見えてわかるから楽しいよ!