跳转到主要内容
CuteJSON
↑↓ 导航 Enter 选择 Esc 关闭

JSON Pointer 与 JSONPath: 区别是什么

发布 1 分钟阅读 作者 Akash Kinkar Pandey

JSON Pointer 和 JSONPath 都处理 JSON 文档内部的位置,并且 都在相同类型的工具中出现: JSON Schema 中的 $ref、PATCH 操作、基于路径的差异。它们解决不同的问题,了解 某个任务实际需要哪一个可以避免选择错误的工具。

JSON Pointer: 一个位置,RFC 6901

指针是由 / 分隔的令牌序列: /user/name 表示 user 对象内的 name 键,/items/0 表示 items 数组的第一个元素。令牌内有两个字符需要转义 (~1 表示 字面量 /,~0 表示字面量 ~),空字符串作为指针 表示整个文档。这就是全部语法。指针精确解析到 一个值,或者失败,中间什么都没有: 没有通配符, 没有过滤器,无法匹配超过它所命名的那个位置。

{ "user": { "name": "Ada", "roles": ["admin", "editor"] } }

/user/name 解析为 "Ada"。/user/roles/1 解析为 "editor"。 /user/email 失败,因为该键不存在。指针 语法中没有任何东西可以在一个表达式中请求“所有角色”; 调用者 必须已经知道索引。

JSONPath: 一种查询语言

JSONPath 标准化为 RFC 9535,专为匹配而构建,而不仅仅是 寻址。$.user.roles[*] 在上面的示例中在一个查询中返回两个角色。 $..email 在文档的每个层级搜索名为 email 的任何键, 无论嵌套多深。像 $.items[?(@.price > 100)] 这样的过滤表达式 根据自身内容的条件选择数组元素。JSONPath 查询可以返回零个匹配、一个或多个,这 与指针的解析或失败的契约根本不同。

实际区别

指针命名你已经知道的位置。JSONPath 查询描述一个 条件,并让引擎找到满足它的内容。这个区别 决定了哪一个适合给定的任务:

  • 你已经确切知道想要哪个值(“发货地址数组的 第三个元素”): 使用指针。它更简单,每个文档有一个 明确的含义,并且所有实现都同意它的功能, 因为 RFC 几乎没有留下方言差异的空间。
  • 你正在搜索匹配条件的值,或者你事先不知道 确切路径(“每个 status 为 failed 的对象, 无论出现在哪里”): 使用 JSONPath。这就是方言 差异开始变得重要的地方: JSONPath 实现比 RFC 9535 自己的示例所暗示的差异更大,因此为一个库编写的查询 不保证在另一个库中行为相同。

实际中各自出现的位置

JSON Patch (RFC 6902) 操作专门使用指针; add、remove、replace 或 move 操作中的每个 "path" 都是 JSON Pointer,因为 patch 操作在设计上针对一个精确位置。JSON Schema 的 $ref 关键字也通过指针语法解析,原因 相同: 模式引用指向一个定义,而不是一组定义。 JSONPath 出现在人或工具需要交互式查询文档的地方: 调试大型 API 响应、从日志中提取字段, 或构建应该匹配任何具有给定形状的文档的规则, 无论相关字段的确切位置在哪里。

尝试两者

JSON Pointer Evaluator 根据文档解析指针, 在查找失败时,报告它到达了哪里以及 该点实际存在哪些键,而不是简单的“未找到”。 JSONPath Tester 使用函数扩展运行 RFC 9535 的文档化 子集,而本站博客上的 JSONPath 速查表 为每个值得了解的选择器提供了实际示例。如何使用 JSON Pointer 更深入地介绍了指针语法本身, 包括转义。

返回所有文章