JSONPath 测试
JSONPath 之于 JSON,相当于 XPath 之于 XML:写一条路径表达式,把想要的节点从一坨 JSON 里挑出来。这里除了结果,还会把每个命中节点的完整路径列出来——写表达式时最费劲的往往不是取值,而是搞清楚自己到底取到了哪一层。
$.store.book[0].title
$..author
$.store.book[*].price
$..book[0:2]
$..book[-1:]
$..book[?(@.price<10)]
$..book[?(@.isbn)]
$..*
语法速查
| 写法 | 含义 | 例子 |
|---|---|---|
| $ | 根节点,表达式都从它开始 | $ |
| .name | 取某个键 | $.store.bicycle |
| ['name'] | 同上,键名里有点或空格时用这种 | $['my key'] |
| ..name | 递归下降,不管埋多深都找出来 | $..price |
| * | 通配,当前层的所有子节点 | $.store.* |
| [n] | 数组下标,负数从末尾数 | $..book[-1] |
| [a,b] | 同时取多个下标或多个键 | $..book[0,2] |
| [start:end:step] | 数组切片,规则和 Python 一样,end 不含 | $..book[0:2] |
| [?(表达式)] | 条件过滤,@ 指当前元素 | $..book[?(@.price<10)] |
过滤支持 == != < <= > >=、&&、||,以及只写 @.isbn 判断字段存不存在。右边的值可以是数字、'字符串'、true/false/null。
几个容易踩的点
- 结果永远是个数组
- 即使只命中一个节点,标准实现也返回长度为 1 的数组。很多人拿
$.a.b的结果直接当对象用,一到生产就undefined。 - JSONPath 没有官方规范
- 它最早只是 2007 年的一篇博文,各语言实现(Jayway、jsonpath-ng、jsonpath-plus…)在切片边界、过滤语法、
$..*的展开顺序上都有出入。跨语言用之前最好先在目标库里试一遍,别只信在线工具。 - 递归下降很贵
$..x要遍历整棵树。配置解析这种一次性场景无所谓,放在每个请求的热路径上就该换成写死的路径。- 和 JSON Pointer 不是一回事
- JSON Pointer(RFC 6901,写法是
/store/book/0/title)只能定位一个节点,没有通配和过滤,但它有正式标准,JSON Patch 用的就是它。 - 相关工具
- JSON 格式化、JSON 结构处理、JSON Schema 校验、JSON 对比、XPath 测试。