
JSONPath、jq 及 JavaScript 路徑有甚麼分別?從 RFC 9535 理解查詢語法
同樣要從 JSON 取出第一件商品的名稱,有些工具使用 $.items[0].name,有些接受 .items[0].name,另一些程式庫則使用 ["items",0,"name"]。寫法相似,並不代表可以直接複製到另一個工具使用。
本文以 RFC 9535 的 JSONPath 為基礎,整理它與 jq 篩選器、JavaScript 屬性存取及 lodash 路徑的分別。理解這些寫法時,應把它們視為由不同引擎解讀的不同語言,而非可以互換的「JSON 地址」。
日文原文發布: 2026-06-09
JSONPath 選取的是 JSON 文件中的節點
JSONPath 是用來選取 JSON 節點的查詢語法。以下面的數據為例,$.items[0].name 會選取第一件商品的名稱。例子的價格沿用日本原文,以日圓計算。
{
"items": [
{ "name": "USB-C 數據線", "price": 1200 },
{ "name": "充電器", "price": 2980 }
]
}
$ 是根節點,.items 選取物件的成員,[0] 選取陣列的第一個元素,.name 再選取當中的名稱。結果選到的值是 "USB-C 數據線"。雖然寫法像檔案路徑,實際上是在查詢 JSON 的樹狀結構。
RFC 9535 訂明了哪些規則?
不同 JSONPath 實作過往有不少差異。2024 年 2 月發佈的 RFC 9535 訂明了共同語法及節點選取規則;較早的實作及各工具的擴充功能,仍須與標準本身分開理解。
如表格未能完整顯示,可左右捲動。
| 寫法 | 意思 | 例子 |
|---|---|---|
$ | 根節點 | $ |
.name | 按名稱選取子節點 | $.items |
['name'] | 以引號指定成員名稱 | $['user.name'] |
[0] | 陣列索引 | $.items[0] |
[*] | 選取所有子節點 | $.items[*].name |
..name | 搜尋後代節點 | $..price |
[?expr] | 按條件篩選 | $.items[?@.price < 2000] |
RFC 不只列出符號,亦把查詢結果定義為「節點清單」(nodelist),以 @ 表示篩選條件中的當前節點,並定義萬用字元及陣列切片等操作。工具聲稱支援 JSONPath,並不表示它已實作 RFC 的所有功能。
$ 是根節點,@ 是當前節點
$ 永遠指向整份文件的根節點。篩選條件中的 @,則指向正在檢查的節點。
$.items[?@.price < 2000].name
這個查詢會逐一檢查 items 中的商品。@.price 代表當前商品的價格,因此會選到 "USB-C 數據線"。如果改寫為 $.price,查詢便會查看根節點下的 price,而上面的數據沒有這個成員。
jq 篩選器與 JSONPath 是兩種語言
jq 的 . 是把輸入原樣傳回的 identity filter,.foo 則取出名為 foo 的成員。.items[0].name 看似 JSONPath,實際上使用的是 jq 語法。jq 除了取值,還可以轉換數據、計算、透過管道串連操作、建立陣列及產生多個輸出。
如表格未能完整顯示,可左右捲動。
| 用途 | JSONPath | jq |
|---|---|---|
| 第一件商品的名稱 | $.items[0].name | .items[0].name |
| 所有商品的名稱 | $.items[*].name | .items[].name |
| 價格低於 2,000 日圓的商品 | $.items[?@.price < 2000] | .items[] | select(.price < 2000) |
表中的比較以前述商品價格均為數值作前提。jq 為不同類型的值訂有大小次序,因此 price 缺少或為 null 時,亦會符合 .price < 2000。如只想比較數值,可先限定類型:.items[] | select(.price | numbers) | select(.price < 2000)。JSONPath 與數值進行大小比較時,並沒有相同的行為。
jq 的 .items[].name 會把每個名稱分別輸出。JSONPath 則傳回節點清單,並不會自動剔除重複節點:對 ["a","b"] 使用 $[0,0],第一個節點會被選取兩次;若以陣列表示選到的值,便是 ["a","a"]。陣列的萬用字元選取保留原有次序,但 RFC 並不保證物件萬用字元選取的成員次序。
JavaScript 屬性存取是會執行的表達式
obj.items[0].name 是 JavaScript 屬性存取。程式執行時會對這個表達式求值;它與交由 JSONPath 引擎解讀的查詢字串不同。
{ "user.name": "阿晴", "user": { "name": "阿朗" } }
$.user.name選取巢狀物件內的名稱,值為"阿朗"。$['user.name']選取名稱包含點號的單一成員,值為"阿晴"。obj.user.name是 JavaScript 對巢狀屬性的存取。obj["user.name"]是 JavaScript 對名稱包含點號的屬性進行存取。
路徑字串可以儲存及傳遞,JavaScript 表達式則會作為程式碼執行。不要直接執行使用者輸入的任意路徑;應先解析明確支援的路徑語法,再逐層存取數據。
lodash 路徑並非標準 JSONPath
_.get(object, path) 接受 "a[0].b.c" 一類字串,亦接受 ["a",0,"b","c"] 一類陣列。它沿屬性路徑取值,但這不代表路徑字串具備 RFC 9535 所定義的意思。
在 items[0].name 這類簡單情況,寫法可能很接近;JSONPath 的萬用字元、後代搜尋及篩選條件,卻不能直接當作 lodash 路徑使用。要明確區分含點號的完整鍵名與巢狀屬性,可以使用路徑陣列:["user.name"] 與 ["user","name"] 表示不同路徑。
在不同工具之間搬用路徑,要留意五個分別
- 根節點符號:RFC 9535 的頂層查詢必須以
$開始,篩選條件內則可從@開始。jq 以.存取輸入,但並非每個 jq 篩選器都以點號開始。 - 逐一處理陣列元素:JSONPath 使用
[*],jq 使用[]。 - 鍵名包含點號:點號如屬名稱的一部分,須以引號包住完整名稱,例如
['user.name']。 - 成員不存在:JSONPath 不會選到任何節點;這與選到一個值為
null的節點不同。 - 篩選條件:JSONPath 的
[?@.x]檢查 x 是否存在,即使其值為false或null亦會選取。jq 的select(.x)則排除 false 及 null,但保留 0 及空字串。這亦與 JavaScript 的真假值判斷不同。
{ "x": null }
以上述物件為輸入,$.missing 選到零個節點,$.x 則選到一個值為 null 的節點。下表 JSONPath 欄的 [] 及 [null],是以陣列表示所選節點的值;不同 API 封裝節點清單的方式可能不同。
如表格未能完整顯示,可左右捲動。
| 處理方式 | 不存在的 missing 成員 | 存在的 x 成員 |
|---|---|---|
| JSONPath | $.missing → [] | $.x → [null] |
| jq | .missing → null | .x → null |
| JavaScript | obj.missing → undefined | obj.x → null |
| lodash | _.get(obj, ["missing"], "預設值") → "預設值" | _.get(obj, ["x"], "預設值") → null |
JavaScript 如繼續存取 obj.missing.name,會拋出 TypeError;使用 obj.missing?.name 則得到 undefined。lodash 只在解析結果為 undefined 時使用預設值,並不會以預設值取代 null。
例如輸入為 [{"x":false},{"x":null},{"x":0},{"x":""},{}],JSONPath 的 $[?@.x] 會選取首四個物件;jq 的 .[] | select(.x) 只輸出 x 為 0 及空字串的兩個物件。檢查 API 回應、分析日誌或編寫自動化測試時,分享路徑應一併註明語言及引擎,避免只稱它為「JSON 路徑」。
顯示數據位置,與執行查詢是兩回事
在畫面上以 items[0].name 標示數據位置,不一定需要完整的 JSONPath 語法。真正用於搜尋、擷取或測試的查詢,則必須配合目標引擎的語法及支援範圍。
NanToo 的 JSONPath Finder 目前只提供日文版。選取樹狀結構中的節點後,工具會並列顯示 JSONPath、JavaScript、Python、jq 及 lodash 五種存取形式,並可逐項複製。查詢欄只支援部分語法,並非完整的 RFC 9535 驗證器。若要在這個工具比較數值,請使用 $.items[?(@.price < 2000)].name;工具要求把條件放在圓括號內,RFC 本身則容許省略。本文的存在篩選、重複選取 $[0,0]、陣列切片及複合條件,均不在該工具的支援範圍。
排查路徑問題前,可先用香港版的 JSON 格式化及驗證工具 檢查輸入,再選擇支援所需查詢的引擎。JSON 格式是否有效,與查詢會如何執行,應分開確認。
參考資料及來源
編輯說明
本文使用 AI 協助編輯,並在發布前由編輯核對。內容仍可能包含事實、理解或時效上的錯誤;作出重要決定前,請查閱所列的一手資料或官方文件。

