JSONPath 语法速查与实战示例
JSONPath 用一行表达式就能从任意 JSON 里取出你要的节点,接口调试、日志排查时经常用到。 本文用一份固定的 store / book 示例数据,把 $、通配、递归、过滤与切片讲清楚, 示例都能在站内 JSONPath 查询工具 里复现。
一、先准备一份示例数据
下面这份数据和站内工作台内置的「填入示例」一致,本文所有表达式都可以直接对 它 执行, 结果与文中一致:
{
"store": {
"book": [
{ "category": "reference", "title": "Sayings", "author": "Nigel Rees", "price": 8.95 },
{ "category": "fiction", "title": "Sword of Honour", "author": "Evelyn Waugh", "price": 12.99 },
{ "category": "fiction", "title": "Moby Dick", "author": "Herman Melville", "price": 8.99 }
],
"bicycle": { "color": "red", "price": 19.95 }
}
}二、JSONPath 的核心语法
一条 JSONPath 表达式始终以 $ (根节点)开头,之后由下面几种「片段」串联而成:
| 写法 | 含义 | 示例 |
|---|---|---|
$ | 根节点 | $ |
.key / ['key'] | 取对象字段 | $.store.bicycle.color |
[i] | 数组下标(负数从末尾数,[0,2] 取并集) | $.store.book[0].title |
[start:end] | 切片,左闭右开 | $.store.book[0:2] |
* | 通配:对象所有子节点 / 数组所有元素 | $.store.book[*].author |
.. | 递归下降:匹配任意层级 | $..price |
[?(...)] | 条件过滤,@ 代表当前节点 | $..book[?(@.price < 10)] |
过滤条件里可用比较 == != < <= > >= 与逻辑 &&||, 也可以只写 @.field 判断字段是否存在。
三、实战:对示例数据逐条运行
下表每一行都可以在上面的示例数据上复现(结果为实际命中值):
| 目标 | 表达式 | 结果 |
|---|---|---|
| 取单个字段 | $.store.bicycle.color | "red" |
| 第一本书的标题 | $.store.book[0].title | "Sayings" |
| 最后一本书 | $.store.book[-1].title | "Moby Dick" |
| 所有作者 | $.store.book[*].author | Nigel Rees、Evelyn Waugh、Herman Melville |
| 递归找所有价格 | $..price | 8.95、12.99、8.99、19.95 |
| 价格低于 10 的书名 | $..book[?(@.price < 10)].title | "Sayings"、"Moby Dick" |
| 分类为 fiction | $..book[?(@.category=="fiction")].title | "Sword of Honour"、"Moby Dick" |
| 前两本书 | $.store.book[0:2].title | "Sayings"、"Sword of Honour" |
四、常见错误与排查
- 没有以 $ 开头。 表达式必须从根节点开始,写
store.book会提示「JSONPath 表达式必须以 $ 开头,例如 $.store.book[0].title」。 - $ 后面直接接名称或字段。
$store不合法,根节点之后只能接.或[,会提示「$ 之后只能接「.」或「[」」。 - 过滤里误用单引号或单个等号。 字符串值要用双引号、比较相等要用
==: 写成[?(@.category='fiction')]或[?(@.price=9)]都会落空。 - 括号或引号未闭合。 少写
]、)或引号不配对时,预检会给出「存在未闭合的「[」」「表达式中的引号未闭合」等中文提示,而非静默返回零结果。 - 把 . 当成 .. 用,层级对不上。 用
$.book[*]找不到数据时,多半是 book 藏在更深的层级;用$..book[*]递归定位真实层级,再写精确路径。
排查建议:先用 $ 确认整体结构,再用 $..字段名 找到目标层级,最后补上 [*] 与过滤条件。命中过多时可缩小路径,页面最多保留前 500 条并提示已截断。
五、速查表
工作台内置的速查卡按「基础 / 通配与递归 / 条件过滤 / 切片」四组给出可运行示例,点击即填入表达式,可对照下表速记:
| 分类 | 表达式 | 说明 |
|---|---|---|
| 基础 | $.store.book[0,2].title | 多个下标并集 |
| 通配 | $.store.* | 对象全部一级子节点 |
| 递归 | $..book[*].title | 递归定位 book 后取字段 |
| 过滤 | $..book[?(@.author && @.price)] | 字段存在性判断 |
| 切片 | $.store.book[-2:].title | 取最后 2 个 |
现在就试一条表达式
粘贴 JSON 即可用 JSONPath 实时取值与过滤,全部在浏览器本地完成,数据不会上传。
常见问题
JSONPath 和 jq 有什么区别?该用哪个?
JSONPath 是纯「路径定位」语言,语法接近 XPath,擅长按路径与条件从 JSON 中选取节点,写法如 $..book[?(@.price<10)],上手快。jq 是完整的数据处理语言,支持管道、map / select、group_by、排序与对象重塑,能力更强但语法更多。本工作台两个引擎在同一页面切换,先用 JSONPath 快速取值,需要加工数据时再切 jq。
表达式明明合法,为什么查不到结果?
表达式合法但没有命中时,状态栏会提示「无匹配:表达式合法,但当前数据中没有符合条件的节点」,而不是报错。常见原因:路径层级与实际 JSON 不一致(可用 $..字段名 递归搜索真实层级)、过滤条件里的字符串与实际大小写或空格不一致、比较字段在部分元素上缺失。可对照本文的示例数据逐条试验。
$..price 和 $.store.book[*].price 有什么区别?
一个点是「下钻一层」,两个点是「递归所有层级」。$..price 会扫描整份文档里任意层级的 price,示例数据里得到 8.95、12.99、8.99、19.95 四条(含 bicycle 的价格);$.store.book[*].price 只取 book 数组内每个元素的 price,只得到前三条。层级明确时用精确路径,层级不确定时先用 .. 定位。
过滤里为什么用双引号,能用单引号吗?
字符串值请用双引号,例如 $..book[?(@.category=="fiction")];比较相等要用 == 而不是 =。本站的表达式预检会检查引号是否闭合、括号是否配平,畸形表达式会直接给出中文提示,而不是静默返回零结果。
查询时我的 JSON 数据会上传吗?结果很多会卡吗?
不会上传。解析与查询都在浏览器本地的 Web Worker 中完成,站点没有后端服务,可打开开发者工具 Network 面板自证。命中结果最多保留前 500 条(超出会提示「已截断到前 500 条」),因此建议尽量用精确路径、少用全文档递归 .. 缩小命中范围。