JSONPath 查詢指南:像專家一樣擷取資料
JSONPath 是一種 JSON 查詢語言,類似於 XPath 之於 XML 的角色。當你面對來自 API 的複雜、深層巢狀 JSON 回應時,JSONPath 讓你能精確擷取所需資料,而無需撰寫迴圈和條件判斷。本指南涵蓋語法、運算子及實際應用模式。
為什麼選擇 JSONPath?
考慮一個典型的巢狀資料 API 回應:
{
"store": {
"books": [
{ "title": "Clean Code", "author": "Robert Martin", "price": 32.99, "tags": ["programming", "best-practices"] },
{ "title": "Design Patterns", "author": "Gang of Four", "price": 44.99, "tags": ["programming", "architecture"] },
{ "title": "The Pragmatic Programmer", "author": "Hunt & Thomas", "price": 39.99, "tags": ["programming", "career"] }
],
"music": [
{ "title": "Kind of Blue", "artist": "Miles Davis", "price": 12.99 }
]
}
}
要取得所有書籍標題,你可以寫一個迴圈——或直接使用 JSONPath:$.store.books[*].title
基本語法
| 表達式 | 說明 |
|---|---|
$ | 根物件 |
. | 子運算子 |
.. | 遞迴下降(搜尋所有層級) |
[*] | 萬用字元(所有元素) |
[n] | 陣列索引(從 0 開始) |
[n,m] | 多重索引 |
[start:end:step] | 陣列切片 |
[?()] | 篩選表達式 |
@ | 目前元素(在篩選器中使用) |
點記法 vs 括號記法
兩種記法都可以存取屬性,但括號記法在遇到特殊字元時是必要的:
# 點記法
$.store.books[0].title
# 括號記法(等效)
$['store']['books'][0]['title']
# 含特殊字元的鍵必須使用括號記法
$['store']['price-range']
陣列操作
索引
$.store.books[0] # 第一本書
$.store.books[-1] # 最後一本書
$.store.books[0,2] # 第一和第三本書
切片
$.store.books[0:2] # 前兩本書(索引 0 和 1)
$.store.books[1:] # 除第一本外的所有書
$.store.books[:2] # 前兩本書
$.store.books[::2] # 每隔一本書
萬用字元
$.store.books[*].title # 所有書籍標題
$.store.* # 所有商店集合(books、music)
$..title # 任意深度的所有標題
$..price # 任意深度的所有價格
遞迴下降運算子(..)特別強大,可以不論階層位置擷取值。
篩選表達式
篩選器根據條件選取元素:
# 價格低於 $40 的書
$.store.books[?(@.price < 40)]
# 特定作者的書
$.store.books[?(@.author == 'Robert Martin')]
# 標籤超過 2 個的書
$.store.books[?(@.tags.length > 2)]
# 擁有 'price' 屬性的書
$.store.books[?(@.price)]
組合篩選器
# 價格低於 $40 且屬於 programming 標籤的書
$.store.books[?(@.price < 40 && @.tags[0] == 'programming')]
實際應用範例
從 API 回應中擷取
GitHub API — 取得所有倉庫名稱:
$[*].name
天氣 API — 取得今日溫度:
$.daily[0].temp.day
電商 API — 取得所有產品圖片:
$.products[*].images[0].url
設定檔擷取
Docker Compose — 取得所有服務名稱:
$.services.*~
Package.json — 取得所有依賴名稱:
$.dependencies.*~
JSONPath vs jq
JSONPath 和 jq 都是 JSON 查詢工具,但它們服務於不同的使用情境:
| 功能 | JSONPath | jq |
|---|---|---|
| 環境 | 函式庫、API | 命令列 |
| 語法 | XPath 風格 | 自訂函數式 |
| 轉換 | 僅查詢 | 查詢 + 轉換 |
| 標準 | RFC 9535 | 事實標準 |
在命令列處理 JSON 時,jq 更為強大。在應用程式中嵌入查詢或使用 Web 工具時,JSONPath 的支援更為廣泛。
使用我們的 JSON Path 探索工具 互動式測試 JSONPath 表達式。貼上你的 JSON,撰寫查詢,即時查看結果。
實作範例
JavaScript (jsonpath-plus)
const { JSONPath } = require('jsonpath-plus');
const result = JSONPath({
path: '$.store.books[?(@.price < 40)].title',
json: data
});
// ["Clean Code", "The Pragmatic Programmer"]
Python (jsonpath-ng)
from jsonpath_ng import parse
expr = parse('$.store.books[*].title')
titles = [match.value for match in expr.find(data)]
RFC 9535:JSONPath 標準
2024 年 2 月,JSONPath 正式被標準化為 RFC 9535。這解決了各實作之間長期存在的不一致問題。主要標準化行為包括:
- 陣列索引從 0 開始
- 篩選表達式使用
@表示目前元素 - 字串比較區分大小寫
- 結果始終是匹配值的陣列
如果你正在選擇 JSONPath 函式庫,請優先選擇支援 RFC 9535 的版本以確保行為一致。
常見問題
JSONPath 和 JSON Pointer 有什麼差別?
JSONPath 是一種查詢語言,可以使用萬用字元和篩選器匹配多個值。JSON Pointer(RFC 6901)是一種簡單的路徑語法,精確定位單一值:/store/books/0/title。需要搜尋或篩選時使用 JSONPath;已知確切路徑時使用 JSON Pointer。
JSONPath 可以修改 JSON 資料嗎?
標準 JSONPath 是唯讀的——它只擷取資料而不修改。某些函式庫擴展了 JSONPath 的 set/delete 操作,但這些不是標準的一部分。如需轉換資料,可以考慮 jq(命令列)或編寫應用程式碼。如需檢視和探索 JSON 結構,我們的 JSON 格式化工具 可以幫助你在撰寫查詢前理解資料。
相關資源
- JSON Path 探索工具 — 在瀏覽器中測試 JSONPath 表達式
- JSON 格式化最佳實踐 — 組織你的 JSON 以便更容易查詢
- JSON Schema 驗證指南 — 驗證你的 JSONPath 查詢所期望的結構