JSON 之 JSONPath 使用详解

阿里云教程4个月前发布 CC蛮
26 0 0

Fastjson2官方文档中提到“在Fastjson2中,JSONPath是一等公民”,看得出来,JSONPath作为处理JSON 的简洁、灵活、类路径的表达式语言愈发被重点关注。

本文将从语法规范、操作符详解、表达式类型、实现差异、高级用法、常见陷阱 等多个维度详解。


一、JSONPath 基础概念

1.1 根节点:$

  • $ 表明 JSON 文档的根对象(或根数组)。
  • 所有路径都从 $ 开始。

示例:

ounter(line
{ "name": "Alice" }
  • $ → 整个对象 { “name”: “Alice” }
  • $.name → “Alice”

1.2 当前节点:@

  • 在过滤表达式中,@ 表明当前正在被评估的节点。
  • 仅在 ?() 过滤器中有效。

示例:

ounter(line
[10, 20, 30]
  • $[?(@ > 15)] → [20, 30]

二、JSONPath 操作符详解

操作符

名称

描述

示例

$

根节点

表明整个 JSON 文档的起点

$.store

@

当前节点

在过滤表达式中引用当前元素

$[?(@.price > 10)]

.

子属性选择器(点表明法)

选择对象的直接子属性

$.store.book

[]

子属性/索引选择器(括号表明法)

支持字符串键、数字索引、表达式

$['store']['book']

或 $[0]

..

递归下降(深度优先遍历)

匹配任意层级下的匹配项

$..author

*

通配符

匹配所有字段或数组元素

$.store.book[*].author

[n]

数组索引

获取数组第 n 个元素(从 0 开始)

$.book[0]

[start:end:step]

切片(Slice)

类似 Python 的切片语法(部分实现支持)

$[1:3]

、$[::-1]

[?(expr)]

过滤表达式

对数组元素进行条件筛选

$[?(@.price < 10)]

,

联合选择(Union)

在 [] 中选择多个键或索引(部分实现支持)

$['name','age']

或 $[0,2]

⚠️ 注意:并非所有实现都支持全部操作符(如切片、联合选择、负索引等)。


三、路径表达式类型详解

3.1 点表明法(Dot-Notation)

  • 适用于键名是合法标识符(不含空格、特殊字符)的情况。
  • 更简洁。

示例:

ounter(line
{ "user": { "name": "Bob" } }
  • $.user.name → “Bob”

3.2 括号表明法(Bracket-Notation)

  • 适用于键名包含空格、特殊字符、数字开头,或动态键名。
  • 更通用。

示例:

ounter(line
{ "user info": { "1st-name": "Bob" } }
  • $['user info']['1st-name'] → “Bob”

✅ 推荐:在不确定键名合法性时,统一使用括号表明法。


3.3 递归下降(..)

  • 从当前节点开始,递归搜索所有子层级中匹配的字段。
  • 超级强劲,但可能性能开销大。

示例:

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
{
  "a": {
    "b": {
      "name": "X"
    }
  },
  "c": {
    "name": "Y"
  }
}
  • $..name → [“X”, “Y”]

⚠️ 注意:$..* 会返回所有值(包括嵌套结构),慎用。


3.4 通配符(*)

  • 匹配当前层级的所有字段(对象)或所有元素(数组)。

示例:

ounter(line
{ "a": 1, "b": 2 }
  • $.* → [1, 2]

数组示例:

ounter(line
[{"x":1}, {"x":2}]
  • $[*].x → [1, 2]

3.5 数组索引与切片

基本索引

  • $[0]:第一个元素
  • $[-1]:最后一个元素(仅部分实现支持,如 Python 的 jsonpath-ng)

切片(Slice)

语法:[start:end:step],语义同 Python。

示例(假设数组长度为 5):

  • $[1:3] → 第 1、2 个元素(不包含索引 3)
  • $[:2] → 前两个元素
  • $[::2] → 所有偶数索引元素
  • $[::-1] → 反转数组(若支持)

❗ 多数 JavaScript 实现(如 jsonpath-plus)不支持切片


3.6 过滤表达式(Filter Expression)

语法:[?(<boolean expr>)]

支持的比较操作符(因实现而异):

  • ==, !=, <, <=, >, >=
  • =~:正则匹配(部分实现支持)
  • in:成员检查(如 @.category in ['fiction', 'sci-fi'])

逻辑操作符:

  • &&(或 and)
  • ||(或 or)
  • !(或 not)

示例

ounter(lineounter(lineounter(lineounter(line
[
  { "name": "Alice", "age": 30 },
  { "name": "Bob", "age": 25 }
]
  • $[?(@.age > 25)] → [{“name”:”Alice”,”age”:30}]
  • $[?(@.name == 'Bob')] → [{“name”:”Bob”,”age”:25}]

正则匹配(Jayway 实现):

  • $[?(@.name =~ /Ali.*/)]

⚠️ 注意:不同库对表达式语法的支持差异很大。例如:

Java (Jayway):支持 =~、empty、size() 等

Python (jsonpath-ng):支持基本比较和逻辑

JS (jsonpath-plus):支持有限比较,不支持正则


3.7 联合选择(Union)

语法:['key1','key2'] 或 [0,2,4]

示例:

ounter(line
{ "a": 1, "b": 2, "c": 3 }
  • $['a','c'] → [1, 3]

数组示例:

ounter(line
["x", "y", "z"]
  • $[0,2] → [“x”, “z”]

✅ 支持情况:Jayway、jsonpath-ng 支持;部分 JS 库不支持。


四、高级功能(依赖具体实现)

4.1 脚本表达式(Script Expression)

某些实现(如 Jayway)允许在路径中嵌入脚本:

  • $[(@.length – 1)] → 获取最后一个元素(通过计算)

4.2 函数支持(Jayway 特有)

  • length():获取数组或字符串长度
    • $.store.book.length() → 2
  • empty():判断是否为空
    • $[?(@.tags empty false)]
  • size():类似 length

4.3 投影(Projection)

非标准但实用的扩展(如 jsonpath-ng.ext):

  • $.store.book[*].{title: @.title, price: @.price}

❗ 标准 JSONPath 不支持对象构造,这是扩展功能。


五、主流实现对比

功能

Jayway (Java)

jsonpath-ng (Python)

jsonpath-plus (JS)

gjson (Go)

$..

递归

✅(但语法不同)

?()

过滤

✅(强劲)

✅(基本)

✅(有限)

=~

正则

切片 [1:3]

负索引 [-1]

✅(通过 #)

联合选择 [0,2]

函数 length()

内置函数

通配符 *

提议:在跨语言项目中,尽量使用 最小子集($, ., [], .., *, ?(@.x > y))以保证兼容性。


六、常见使用场景与表达式模板

场景

JSONPath 表达式

获取所有 ID

$..id

获取第一个用户

$.users[0]

获取价格在 10~20 之间的商品

$[?(@.price >= 10 && @.price <= 20)]

获取嵌套对象中的 name

$..profile.name

获取所有非空标签

$[?(@.tags && @.tags.length > 0)]

获取特定键的值(键含空格)

$['my key']['sub key']

获取数组最后元素(Python)

$[-1]

获取所有书的作者和标题

$..book[*]['author','title']

(若支持联合)


七、常见陷阱与注意事项

  1. 路径不存在 ≠ 错误
  2. 多数实现返回空数组 [],而非抛异常。
  3. 需要显式检查结果是否为空。
  4. 递归下降性能问题
  5. $..* 在大型 JSON 中可能导致 O(n²) 遍历。
  6. 字符串比较 vs 数值比较
  7. @.price == '10' 与 @.price == 10 结果不同(类型敏感)。
  8. 键名大小写敏感
  9. $.Name ≠ $.name
  10. 数组 vs 对象混淆
  11. 对象不能用数字索引:$.obj[0] 无效(除非 obj 是数组)
  12. 转义字符
  13. 若键名含单引号,需转义:$['O'Reilly']

八、调试与测试工具

  1. 在线解析器
  2. https://jsonpath.com/ (基于 jsonpath-plus)
  3. https://jsonpath.herokuapp.com/ (Jayway 实现)
  4. 命令行工具
  5. jp(Go 编写):echo '{“a”:1}' | jp a
  6. jq 虽非 JSONPath,但功能更强(推荐搭配使用)

九、JSONPath vs jq

特性

JSONPath

jq

标准化

无正式标准

广泛使用,实际标准

功能

查询为主

查询 + 转换 + 构造

语法

类 XPath

类函数式编程

学习曲线

中高

适用场景

简单提取

复杂数据处理

提议:简单提取用 JSONPath,复杂处理用 jq。


十、总结

JSONPath 是一个轻量级、直观的 JSON 查询语言,适用于:

  • API 响应字段提取
  • 配置文件解析
  • 自动化测试中的断言
  • 日志分析中的字段抽取
© 版权声明

相关文章

暂无评论

none
暂无评论...