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[*].authorNigel Rees、Evelyn Waugh、Herman Melville
递归找所有价格$..price8.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 条」),因此建议尽量用精确路径、少用全文档递归 .. 缩小命中范围。

相关工具