JSONPath 测试器

对 JSON 运行路径表达式

正在加载工具…

关于 JSONPath 在线测试

JSONPath 测试器在浏览器内对 JSON 文档求值一条 JSONPath 表达式,并把选中的值以 JSON 数组形式输出。文档面板在你运行之前就会提示 JSON 能否解析,结果则始终是数组,即使只命中一个值或一个都没命中。

JSONPath 并不像 XPath 那样是一份标准。Stefan Gössner 在 2007 年的文章里把它描述为 JSON 版的 XPath,此后十七年间每个实现都按自己的理解填补空白:过滤器能不能写任意表达式、负数下标算不算倒数、递归下降要不要进入数组元素。2024 年 2 月发布的 RFC 9535 才给出规范化文法,但生产环境里绝大多数库都早于它,至今保留各自的历史行为。本测试器跑的是 jsonpath-plus,准备上线的表达式请再用目标库验一遍。

如何使用这个开发者工具

  1. 把一份有代表性的文档粘贴到 JSON 面板,先确认头部提示它有效。
  2. 在「JSONPath 表达式」输入框里从根符号 $ 开始书写查询。
  3. 运行查询;结果永远是 JSON 数组,命中一个值时表现为只有一个元素的数组。
  4. 把测试数据改成难对付的形态——缺字段、空数组、多出一个元素——再用同一条表达式跑一遍。
  5. 把表达式复制进代码后,再用运行时实际使用的 JSONPath 库验证一次。

实例:过滤数组,同时容忍缺失的字段

这份书目里有四本书,其中一本完全没有 price 字段,另外还有一辆同样带 price 的自行车。表达式要从价格高于阈值的书里取出书名。

文档与表达式
Expression: $.store.books[?(@.price > 40)].title

{
  "store": {
    "books": [
      { "title": "Clean Code", "price": 30, "tags": ["craft"] },
      { "title": "Refactoring", "price": 45 },
      { "title": "Domain-Driven Design", "price": 52 },
      { "title": "Internal Draft" }
    ],
    "bicycle": { "color": "red", "price": 120 }
  }
}
匹配结果
[
  "Refactoring",
  "Domain-Driven Design"
]

第四本书没有 price,于是 @.price 取到 undefined,比较结果为假,且不会报错——把字段名拼错,得到的是一模一样的沉默。自行车标价 120 却没有出现,因为路径锚定在 $.store.books 上;若写成 $..[?(@.price > 40)],它同样会被选中。

JSONPath 语法与上例文档的实际结果

第三列的每条表达式都是在实例那份书目上真实跑出来的,只替换表达式即可逐行复现。

语法选中什么示例与结果
$文档根节点,所有表达式都从这里开始$ 返回整个对象,包在一个单元素数组里
.key 或 ['key']当前节点下某个具名子节点$['store']['books'][1].title 得到 ["Refactoring"]
..key当前节点之下任意深度的同名键$..price 得到 [30, 45, 52, 120]
*当前节点的全部子节点$.store.books[*].title 得到全部四个书名
[n]按从零开始的下标取一个数组元素$.store.books[0] 得到第一本书的对象
[start:end]切片,右端不含$.store.books[0:2].title 得到前两个书名
[-n:]最后 n 个元素$.store.books[-1:].title 得到 ["Internal Draft"]
[a,b]两个下标或两个键名的并集$.store.books[0,2] 得到第一本和第三本书
[?(表达式)]只保留表达式为真的那些元素$.store.books[?(@.price > 40)].title 得到两个书名

常见问题排查

在这里跑得好好的表达式,到应用里却什么都取不到。

成因 方言差异。Jayway JsonPath、Python 的 jsonpath-ng、Go 的各种实现,以及按 RFC 9535 写的解析器,对过滤器语法、是否允许脚本表达式、以及「当前节点是对象而非数组时过滤器怎么办」各执一词。

解决办法 以实际部署的库为准:写一份能复现差异的最小样例,在两边各跑一次。尽量只使用保守子集——属性访问、通配符、下标、切片和简单比较过滤器——这部分几乎所有实现都一致。

键名拼错了,返回的是空数组而不是报错。

成因 JSONPath 没有模式概念,也没有「必需路径」的说法。选不到东西的表达式是一次成功的零结果查询,这和一条本来就不可能命中的路径在结果上无法区分。

解决办法 在消费端断言结果长度,而不是直接取下标零的值。在这里排查时把表达式从尾部逐段砍短,直到开始有返回值,最后砍掉的那一段就是出问题的位置。

负数下标什么也选不到。

成因 在 jsonpath-plus 中,裸写的负数下标(例如 $.store.books[-1])并不表示倒数,会返回空数组;切片写法 $.store.books[-1:] 才能取到最后一个元素。其他库则接受裸写形式。

解决办法 取最后一个用 [-1:],取最后两个用 [-2:]。需要跨方言可靠时,先选出整个数组,再在应用代码里取末尾元素。

结果是一个扁平列表,分不清每个值来自哪个父节点。

成因 默认结果类型是匹配到的值,所以 $..price 返回四个数字,却看不出其中一个属于自行车而不是书。

解决办法 改为选中容器对象而不是叶子节点——写 $.store.books[?(@.price > 40)] 而不加 .title 后缀——再从每个对象里读需要的字段。

适合用这个工具的场景

  • 排查对接问题时,从层层嵌套的 API 响应里精确取出某一个字段。
  • 在抽取表达式写进测试断言、Postman 脚本或日志流水线之前,先证明它是对的。
  • 上游改了响应结构之后,确认已有的查询是否仍然能解析到目标。
  • 面对陌生载荷时,把表达式一步步放宽,摸清某个值究竟藏在哪一层。

应该换用别的工具的场景

  • 诊断文档为什么解析不了。本工具只给出有效或无效两种状态,精确的错误偏移量请用 JSON 格式化工具查看。
  • 重塑数据结构。JSONPath 只能选取已有的值,不能构造新对象;表格导出请用 JSON 转表格工具,真正的变换请用 jq。
  • 比较两份载荷之间的差异,那是文本比较工具的职责。

隐私与数据处理

文档解析与表达式求值都由 jsonpath-plus 在当前浏览器标签页内完成。没有上传,不跨访问保存,过滤器表达式也是在本地求值而不是发往任何地方。生产载荷里几乎总带着客户标识和访问令牌,粘贴前请把文档裁剪到只剩你需要的结构。

相关开发者工具

常见问题

JSONPath 有官方规范吗?

现在有了。RFC 9535 于 2024 年 2 月发布,定义了规范化的文法与语义。它比最初那篇文章晚了十七年,因此绝大多数已部署的库都是照着非正式描述实现的,至今各行其是。把它当作未来的方向,而不是对你当前运行时行为的描述。

为什么结果总是数组?

测试器请求的是包装后的结果,所以命中一个值时返回单元素数组,什么都没命中时返回空数组。这样「零结果」是看得见的,而不是显示一个裸 null,同时也与多数 JSONPath 库的默认行为一致。

$.store.books 和 $..books 有什么区别?

前者是精确路径,只把 books 当作 store 的直接子节点来找。后者是递归下降,会在任意深度找出每一个 books 键。递归下降在探索阶段方便,上线则有风险:日后结构一变,多出来的第二个 books 键会被你的查询悄悄捎上。

过滤器里能写函数调用或正则吗?

在 jsonpath-plus 里可以,例如 [?(@.title.match(/^R/))] 能跑通,因为表达式按 JavaScript 求值。但这是实现特性而非可移植特性。RFC 9535 改为定义一小组固定函数,很多库则干脆拒绝脚本表达式。

JSONPath 和 jq 有什么不同?

JSONPath 是一门选择语言:它指明已有文档中的位置,返回那里的值。jq 则是变换语言,有管道、算术、条件判断和对象构造。要改字段名或算总计,需要的是 jq 或应用代码,而不是 JSONPath。

返回空结果是不是说明我的 JSON 有问题?

不是。JSON 无效会在查询运行之前由文档面板报出来。空数组意味着文档解析正常、表达式没匹配到任何东西,这是完全正常的结果——缺一个可选字段和拼错一个键名,产生的都是这个。