JSONPath Tutorial: Query JSON Like a Pro
Master JSONPath syntax with practical examples. Learn every operator, filter expression, and real-world query pattern to extract data from complex JSON structures.
JSONPathとは?
JSONPathはJSONのクエリ言語であり、XMLに対するXPathのようなものです。複雑なJSON構造にアクセスし、必要なデータを簡潔な表現構文を使用して引き出すことができます。ネストされたオブジェクトや配列を掘り下げるためにループや条件文を書く代わりに、$.store.book[?(@.price < 10)].titleのような単一のパス式を書くだけで、10ドル未満のすべての書籍のタイトルを取得できます。
Stefan Goessnerは2007年にJSONPathを導入し、それ以来、言語やツールを超えた事実上の標準となっています。REST API、設定ファイル、または非自明なJSONデータを扱う場合、JSONPathは大幅に時間を節約してくれます。
JSONPathとXPath: 簡単な比較
XPathを既に知っている場合、JSONPathは馴染みやすいでしょう。主な違いは、JSONが要素、属性、名前空間ではなく、オブジェクトと配列というよりシンプルなデータモデルを持っていることです。以下は両者の比較です:
| 概念 | XPath | JSONPath |
|---|---|---|
| ルート | / | $ |
| 子 | /child | .child または ['child'] |
| 再帰的降下 | // | .. |
| ワイルドカード | * | * |
| 配列インデックス | [1] (1ベース) | [0] (0ベース) |
| フィルタ | [predicate] | [?(expression)] |
完全なJSONPath演算子リファレンス
すべてのJSONPath式はルート$から始まり、演算子をチェーンしてさらに深くナビゲートします。知っておくべきすべての演算子は以下の通りです:
| 演算子 | 説明 | 例 |
|---|---|---|
$ | ルートオブジェクトまたは配列 | $ — ドキュメント全体 |
.key | 名前による子メンバー(ドット表記) | $.store.name |
['key'] | 名前による子メンバー(ブラケット表記) | $['store']['name'] |
.. | 再帰的降下 — すべての子孫を検索 | $..price — すべての「price」フィールド |
* | ワイルドカード — オブジェクトまたは配列のすべてのメンバー | $.store.* |
[n] | 配列インデックス(0ベース) | $.items[0] |
[start:end] | 配列スライス(終了は排他的) | $.items[0:3] — 最初の3つのアイテム |
[start:end:step] | ステップ付き配列スライス | $.items[::2] — 毎回のアイテム |
[n,m] | 複数の配列インデックス | $.items[0,2,4] |
[?()] | フィルタ式 | $.items[?(@.price > 10)] |
@ | 現在のノード(フィルタ内で使用) | @.name == 'Alice' |
サンプルJSON
このチュートリアル全体で使用するJSONドキュメントです。小さな書店APIのレスポンスを表しています:
{
"store": {
"name": "TechBooks Online",
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95,
"inStock": true
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99,
"inStock": false
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99,
"inStock": true
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99,
"inStock": true
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
実用的なJSONPathの例
1. 店の名前を取得
$.store.name
結果:
"TechBooks Online"
2. すべての書籍のタイトルを取得
$.store.book[*].title
結果:
[
"Sayings of the Century",
"Sword of Honour",
"Moby Dick",
"The Lord of the Rings"
]
3. 最初の書籍を取得
$.store.book[0]
結果: 最初の書籍オブジェクト全体。
4. 最後の書籍を取得
$.store.book[-1]
負のインデックスは末尾から数えます。-1は最後の要素を返します。
5. スライス: 最初の2冊の書籍
$.store.book[0:2]
インデックス0と1の書籍を返します。終了インデックスは排他的で、PythonやJavaScriptのslice()と同様です。
6. ドキュメント全体のすべての価格を取得
$..price
結果:
[8.95, 12.99, 8.99, 22.99, 19.95]
再帰的降下演算子..は、深さに関係なくすべてのpriceフィールドを見つけます — 自転車の価格も含まれます。
7. フィルタ: 10ドル未満の書籍
$.store.book[?(@.price < 10)]
価格が8.95と8.99の2冊の書籍を返します。@記号は評価中の現在のアイテムを指します。
8. フィルタ: ISBNを持つ書籍
$.store.book[?(@.isbn)]
モビー・ディックと指輪物語のみを返します。
9. フィルタ: 在庫のあるフィクションの書籍
$.store.book[?(@.category == 'fiction' && @.inStock == true)]
&&(かつ)や||(または)で条件を組み合わせることができます。
10. 複数のインデックス
$.store.book[0,3]
特定の要素を選択します。最初と4番目の書籍を返します。
11. オブジェクトのワイルドカード
$.store.bicycle.*
結果:
["red", 19.95]
自転車オブジェクトのすべての値を返します。
12. 高価な書籍の著者を取得
$.store.book[?(@.price > 15)].author
結果:
["J. R. R. Tolkien"]
自分で試してみてください: 上記のサンプルJSONを貼り付けて、JSONPathテスターでこれらの式を試してみてください。
フィルタ式の詳細
フィルタ式はJSONPathの最も強力な部分です。[?()]内に存在し、各要素に対してブール条件を評価します。使用できる演算子は以下の通りです:
| 演算子 | 意味 | 例 |
|---|---|---|
== | 等しい | @.status == 'active' |
!= | 等しくない | @.role != 'admin' |
> | より大きい | @.age > 18 |
>= | より大きいまたは等しい | @.score >= 90 |
< | より小さい | @.price < 50 |
<= | より小さいまたは等しい | @.quantity <= 0 |
=~ | 正規表現マッチ(実装による) | @.name =~ /^J.*/ |
&& | 論理AND | @.price > 5 && @.price < 20 |
| ` | ` |
一般的なパターンは、プロパティの存在を確認することです。比較演算子なしで@.isbnを書くと、プロパティが存在し、nullでない場合にtrueを返します。
実世界のシナリオ
APIレスポンスからすべてのメールを抽出
ユーザー管理APIからのレスポンスに深くネストされた連絡先オブジェクトが含まれているとします:
{
"users": [
{
"name": "Alice",
"contacts": { "email": "alice@example.com", "phone": "555-0101" }
},
{
"name": "Bob",
"contacts": { "email": "bob@example.com", "phone": "555-0102" }
}
]
}
クエリ: $..email
結果:
["alice@example.com", "bob@example.com"]
再帰的降下演算子は、階層内のどこにあってもすべてのemailフィールドを見つけます。
価格範囲による製品の検索
$.products[?(@.price >= 25 && @.price <= 100)]
製品リストをレンダリングする前に、クライアント側でAPIレスポンスをフィルタリングする際に便利です。
ネストされた設定値を取得
$.config.database.connections[0].host
config?.database?.connections?.[0]?.hostのように、チェーンされたオプショナルアクセスを書くことなく設定ファイルに掘り下げます。
異なる言語におけるJSONPath
JavaScript / Node.js
jsonpath-plusパッケージが最も人気のある実装です:
import { JSONPath } from "jsonpath-plus";
const data = { store: { book: [{ title: "Moby Dick", price: 8.99 }] } };
const titles = JSONPath({ path: "$.store.book[*].title", json: data });
console.log(titles); // ["Moby Dick"]
Python
標準準拠の実装にはjsonpath-ngを使用します:
from jsonpath_ng.ext import parse
data = {"store": {"book": [{"title": "Moby Dick", "price": 8.99}]}}
expr = parse("$.store.book[*].title")
matches = [match.value for match in expr.find(data)]
print(matches) # ['Moby Dick']
Java
Jayway JSONPathライブラリはJVMプロジェクトのための選択肢です:
import com.jayway.jsonpath.JsonPath;
String json = "{\"store\":{\"book\":[{\"title\":\"Moby Dick\",\"price\":8.99}]}}";
List<String> titles = JsonPath.read(json, "$.store.book[*].title");
System.out.println(titles); // [Moby Dick]
注意点と制限事項
JSONPathは強力ですが、プロダクションで依存する前に注意すべき点がいくつかあります:
- 標準仕様がない(最近まで)。 JSONPathは非公式に定義されており、異なるライブラリが微妙な違いで実装しています。IETFは2024年にRFC 9535を発表し、構文を標準化しましたが、多くのライブラリは元のGoessner仕様に従っています。常にライブラリのドキュメントを確認して、サポートされている機能を確認してください。
- 正規表現のサポートが異なる。
=~正規表現演算子は普遍的にサポートされていません。Jayway Javaライブラリはこれをサポートしていますが、多くのJavaScriptライブラリはサポートしていません。 - 書き込み操作はできない。 JSONPathは読み取り専用です。元のドキュメントを変更するために使用することはできません。変更にはJSON Patch(RFC 6902)または手動のトラバーサルが必要です。
- 巨大なドキュメントでのパフォーマンス。 再帰的降下(
..)はツリー内のすべてのノードをスキャンします。数百万のノードを持つドキュメントでは、これが遅くなる可能性があります。パフォーマンスが重要な場合は、特定のパスを優先してください。 - 返り値の型の不一致。 一部のライブラリは、単一の一致に対して単一の値を返し、複数の一致に対して配列を返します。他のライブラリは常に配列を返します。驚きを避けるために、コード内で返り値の型を正規化してください。
- キーに特殊文字が含まれる。 JSONキーにドット、スペース、または他の特殊文字が含まれている場合は、ブラケット表記を使用してください:
$('my.key')ではなく$.my.keyを使用します。
JSONPathとjq
JSONPathと人気のコマンドラインJSONプロセッサであるjqを比較したくなるかもしれません。短い答えは、彼らは似たような問題を解決しますが、異なるオーディエンスのために設計されています。
- JSONPathはアプリケーションコードに埋め込むために設計されています。すべての主要な言語でライブラリサポートがあり、簡潔なクエリ構文を持っています。
- jqは完全なデータ変換言語です。JSONをフィルタリング、マッピング、リデュース、形状変更できます。より強力ですが、学習曲線が急で、主にコマンドラインで使用されます。
アプリケーション内のデータをクエリするには、JSONPathが実用的な選択です。シェルスクリプトやデータパイプラインには、jqが優れています。
クイックリファレンス チートシート
| したいこと | JSONPath |
|---|---|
| ドキュメント全体 | $ |
| 特定のプロパティ | $.user.name |
| 配列内のすべてのアイテム | $.items[*] |
| 最初のアイテム | $.items[0] |
| 最後のアイテム | $.items[-1] |
| アイテムの範囲 | $.items[1:4] |
| 毎n番目のアイテム | $.items[::2] |
| どこにでもある「name」フィールド | $..name |
| 値でフィルタ | $.items[?(@.price < 10)] |
| 存在でフィルタ | $.items[?(@.discount)] |
| 複数の条件 | $.items[?(@.qty > 0 && @.active)] |
自分で試してみてください: JSONPathテスターを開いて、リアルタイムで自分のJSONデータに対してクエリを実行してください。