惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
IT之家
IT之家
博客园_首页
博客园 - 【当耐特】
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
G
Google Developers Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recent Announcements
Recent Announcements
F
Fortinet All Blogs
GbyAI
GbyAI
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
I
InfoQ
H
Help Net Security
T
Tailwind CSS Blog
B
Blog RSS Feed
Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
博客园 - 叶小钗
雷峰网
雷峰网
量子位

博客园 - 漫思

python使用.env构建开发和生产环境 python项目的构建 nodejs构建CICD时的思考  成为 AI 智能体工程师的 10 个步骤 es6的 yield python 中的 yield 笔记本的A壳 thinkpad 更换 reduce() in Python python的字段赋值和取值的操作 python的语法类似于lodash分组展开,合并分组操作 SelectMany C# lodash 数组的常用做法 lodash里面的常用方法 技术的边界 Reduce 和 Transduce 的含义 尤雨溪创办的 VoidZero 官宣加入 Cloudflare,前端 Vite 等保持开源 Ramda 函数库参考教程 ramda es 数组的方法 flatmap map object.entity的教程 Map与FlatMap:在数据处理中的区别与联系 flat、flatmap与map的用法区别1 flat、flatmap与map的用法区别 AI不是从天而降,它经历了七十年三起三落:读懂AI的第三课 Agent 17 种架构模式 分析 & 思考 只有踩过坑才懂:前端生成唯一 ID,别用 Date.now ()了!试试它crypto.randomUUID() FastAPI python并发 代码是 AI 写的,生产事故谁背锅? AI Agent 走出 Demo 幻觉的唯一解药:Harness Engineering
RFC 9535:JSONPath 的标准化之路
漫思 · 2026-04-09 · via 博客园 - 漫思

从 Stefan Gössner 2007 年的博客文章,到 2024 年正式成为 IETF 标准,JSONPath 走过了 17 年的标准化历程。本文带你深入了解 RFC 9535 的核心特性,并用 snack4-jsonpath 实战演示。

1. 为什么需要 JSONPath?

在 JSON 统治 API 世界的今天,我们几乎每天都在处理 JSON 数据。你是否遇到过这样的场景:

  • 从复杂的嵌套 JSON 中提取特定字段
  • 在多层嵌套的数组中筛选符合条件的元素
  • 对 API 返回的 JSON 进行灵活的数据转换

传统的方案要么需要编写大量代码遍历解析,要么依赖不兼容的各种实现。RFC 9535 的出现,终于结束了这种混乱局面。

2. RFC 9535 是什么?

RFC 9535 是 IETF(互联网工程任务组)于 2024 年 2 月正式发布的标准规范,全称:

JSONPath: Query Expressions for JSON

即「用于 JSON 的查询表达式」

该规范由三位作者共同编写:

  • Stefan Gössner — JSONPath 的创始人,早在 2007 年就提出了这一概念
  • Glyn Normington — RFC 编辑
  • Carsten Bormann — RFC 编辑

核心定义

RFC 9535 的核心可以概括为:

JSONPath 定义了一种字符串语法,用于从给定的 JSON 值中选择和提取 JSON 值。

简单来说,JSONPath 就是 JSON 的「XPath」——用类似路径表达式的方式查询 JSON 数据。

3. JSONPath vs 其他方案

标准化 RFC 9535 (2024) AWS 标准 RFC 6901 语法风格 类似 XPath 函数式 路径式 递归下降 ✅ .. ✅ ** ❌ 过滤能力 ✅ 强大 ✅ 强大 ❌ 简单查找 数组切片 ✅ ❌ ❌ 函数扩展 ✅ ✅ ❌
特性JSONPathJMESPathJSON Pointer

4. 核心语法一览

4.1 基本选择器

import org.noear.snack4.jsonpath.JsonPath;

String json = "{\"store\":{\"book\":[{\"author\":\"张三\",\"price\":8.95},{\"author\":\"李四\",\"price\":12.99}],\"bicycle\":{\"color\":\"red\",\"price\":399}}}";

4.2 通配符选择器

import org.noear.snack4.jsonpath.JsonPath;

// 选择所有子节点
JsonPath.select(json, "$.store.*");     // [数组, 对象] - store 下的所有成员

4.3 索引与数组切片

import org.noear.snack4.jsonpath.JsonPath;

// 索引选择(从 0 开始)
JsonPath.select(json, "$.store.book[0]");      // 第一本书
JsonPath.select(json, "$.store.book[-1]");     

4.4 递归下降 ..

这是 JSONPath 最强大的特性之一:

// 递归查找所有 author 字段
JsonPath.select(json, "$..author");     // ["张三", "李四"]

// 递归查找所有 price 字段
JsonPath.select(json, "$..price");      

4.5 过滤表达式 [?(...)]

RFC 9535 的过滤表达式使用 @ 代表当前节点:

// 基础比较
JsonPath.select(json, "$.store.book[?(@.price < 10)]");
// 结果:[{"author":"张三","price":8.95}]

// 字符串匹配
JsonPath.select(json, "$.store.book[?(@.author == '张三')]");

5. 函数扩展

RFC 9535 定义了标准函数扩展接口,snack4-jsonpath 完整实现:

5.1 内置函数

// length() - 获取长度
JsonPath.select(json, "length($.store.book)");    // 2

// count() - 计数(RFC 9535)
JsonPath.select(json, "count($.store.book)");      

5.2 字符串函数

// match() - 正则匹配(需启用完整模式)
JsonPath.select(json, "$.store.book[?match(@.author, '张.*')]");

// search() - 搜索(包含)
JsonPath.select(json, "$.store.book[?search(@.author, '三')]");

5.3 扩展聚合函数(Jayway 风格)

// min() / max() / avg() / sum()
String enhancedJson = "{\"prices\":[8.95,12.99]}";

JsonPath.select(enhancedJson, "$.prices.min()");  

6. 操作符详解

6.1 RFC 9535 标准操作符

// 比较操作符
@.price == 10      // 等于
@.price != 10      

6.2 扩展操作符(Jayway 风格)

// 正则匹配
@.author =~ /张.*/

// 集合操作
@.status in ["active", "pending"]
@.age nin [10, 20]              

7. 实际应用场景

7.1 API 响应解析

String apiResponse = """
{
  "code": 200,
  "data": {
    "users": [
      {"id": 1, "name": "Alice", "orders": [{"amount": 100}, {"amount": 200}]},
      {"id": 2, "name": "Bob", "orders": [{"amount": 150}]},
      {"id": 3, "name": "Charlie", "orders": []}
    ]
  }
}
""";

7.2 配置管理

String config = """
{
  "environments": {
    "dev": {"host": "localhost", "port": 8080},
    "staging": {"host": "staging.example.com", "port": 80},
    "prod": {"host": "prod.example.com", "port": 443, "ssl": true}
  },
  "current": "prod"
}
""";

7.3 数据校验与转换

// 提取并验证数据
String json = """
{
  "products": [
    {"name": "笔记本", "price": 4999, "stock": 100},
    {"name": "鼠标", "price": 99, "stock": 0}
  ]
}
""";

8. snack4-jsonpath 的双模式支持

snack4-jsonpath 同时支持 RFC 9535(IETF)模式和 Jayway 模式

8.1 模式差异

过滤行为 仅过滤子节点 递归过滤当前及子节点 .. 行为 RFC 标准语义 扩展语义 扩展操作符 支持(但不属于规范) ✅ 支持 扩展函数 支持(但不属于规范) ✅ 支持
特性RFC 9535 (默认)Jayway 模式

8.2 模式切换

import org.noear.snack4.Options;
import org.noear.snack4.Feature;

// RFC 9535 模式(默认)
JsonPath jp1 = JsonPath.parse("$.store.book[?(@.price > 10)]");

9. 语法速查表

$ 根节点 $@ 当前节点(过滤中) [?(@.price > 10)].key 子属性 $.store.book['key'] 括号记法 $['store']['book']* 通配符 $.store.*[0] 索引 $.book[0][-1] 末尾索引 $.book[-1][start:end] 切片 $.book[0:2][::step] 步长 $.book[::2]..key 递归下降 $..author[?()] 过滤表达式 [?(@.price < 10)], 多选 ['a','b']length() 长度函数 length($.items)count() 计数函数 count($.items)
语法说明示例

10. 与 XPath 的渊源

RFC 9535 附录 B 专门讨论了 JSONPath 与 XPath 的关系。

JSONPath 从 XPath 汲取了大量灵感:

/$ 文档根 ./@ 当前节点 ** 通配符 //.. 递归下降 [@attr='v'][?(@.attr=='v')] 过滤条件 path/a/bpath.a.b 子路径
XPathJSONPath含义

但 JSONPath 有自己的特色:

  • 更简洁的语法
  • 原生支持数组索引和切片
  • 针对 JSON 结构优化的查询语义

11. 标准化带来的好处

11.1 跨平台一致性

以前:同一段 JSONPath 表达式在不同库中可能有不同的行为。

现在:遵循 RFC 9535 的实现必须产生一致的输出。

11.2 正式测试套件

RFC 9535 配套了官方的 JSONPath Compliance Test Suite (CTS),实现者可以用它验证规范符合度。

11.3 安全考虑

RFC 9535 第 4 节专门讨论了安全问题:

  • 查询注入:恶意构造的查询可能耗尽资源
  • 路径遍历:类似文件系统的 .. 攻击
  • 正则表达式 DoS:复杂正则可能导致 ReDoS

snack4-jsonpath 通过以下方式应对:

// 可选的异常抑制
Options opts = new Options(Feature.JsonPath_SuppressExceptions);

12. 进阶技巧

12.1 链式查询

String json = """
{
  "users": [
    {"name": "Alice", "age": 30, "city": "Beijing"},
    {"name": "Bob", "age": 25, "city": "Shanghai"}
  ]
}
""";

12.2 路径归一化

// 获取归一化路径(Normalized Path)
String path = JsonPath.select(json, "$.users[0].name").getPath();

12.3 动态路径构建

// 解析后缓存,可重复使用
JsonPath path = JsonPath.parse("$.store.$.category[*]");

结语

RFC 9535 的发布标志着 JSONPath 进入了一个新的时代。从 2007 年的博客文章到 2024 年的 IETF 标准,这条路走了整整 17 年。

标准化的价值在于:

  • 开发者可以编写一次,到处运行
  • 工具厂商有了统一的规范遵循
  • 新实现有了明确的参考

snack4-jsonpath 作为 RFC 9535 的 Java 实现,不仅完整支持了标准规范,还通过 Jayway 兼容模式保留了扩展功能。无论你是需要标准兼容性还是扩展能力,都能找到合适的方案。

相关资源