跳到主要内容
JsonPath 表达式核心用法与实战指南 | 极客日志
Java java
JsonPath 表达式核心用法与实战指南 JsonPath 是用于检索和设置 JSON 数据的表达式语言,支持点符号和括号符号。涵盖操作符、函数、过滤器及常见用法,重点讲解 ReadContext 复用优化、MappingProvider 类型转换、自定义 Predicate 断言以及配置选项如 AS_PATH_LIST 和缓存机制,帮助开发者高效处理 JSON 数据解析任务。
RustyLab 发布于 2025/2/4 更新于 2026/4/25 4 浏览概述
JsonPath 类似于 XML 中的 XPath,主要用于路径检索或设置 JSON 数据。它支持两种语法风格:点符号(dot-notation)和括号符号(bracket-notation),例如 $.store.book[0].title 或 $['store']['book'][0]['title']。
基础操作符
符号 描述 $ 查询的根节点对象,表示整个 JSON 数据(数组或对象) @ 过滤器断言处理的当前节点对象,类似 Java 中的 this * 通配符,匹配任意名称或数字 .. 递归搜索(Deep scan),在任何需要名称的地方可用 . 表示一个子节点 ['' (, '')] 表示一个或多个子节点 [ (, )] 表示一个或多个数组下标 [start:end] 数组片段切片,区间为 [start, end),不包含 end [?()] 过滤器表达式,结果必须为 boolean
内置函数
这些函数可在 JsonPath 表达式执行后调用,输入值为表达式的结果。
名称 描述 输出类型 min() 获取数值类型数组的最小值 Double max() 获取数值类型数组的最大值 Double avg() 获取数值类型数组的平均值 Double stddev() 获取数值类型数组的标准差 Double length() 获取数值类型数组的长度 Integer
过滤逻辑
过滤器是用于筛选数组的逻辑表达式。典型形式如 [?(@.age > 18)],可以通过逻辑运算符 && 或 || 组合多个条件。字符串需用单引号或双引号包围,例如 [?(@.color == 'blue')]。
操作符 描述 == 等于(注意数字 1 不等于字符 '1') != 不等于 < / <= 小于 / 小于等于 > / >= 大于 / 大于等于 =~ 正则匹配,例如 [?(@.name =~ /foo.*?/i)] in 包含于,例如 [?(@.size in ['S', 'M'])]
实战示例 {
"store" : {
"book" : [
{ "category" : "reference" , "author" : "Nigel Rees" , "title" : "Sayings of the Century" , "price" : 8.95 } ,
{ "category" : "fiction" , "author" : "Evelyn Waugh" , "title" : "Sword of Honour" , "price" : 12.99 } ,
{ "category" : "fiction" , "author" : "Herman Melville" , "title" : "Moby Dick" , "isbn" : "0-553-21311-3" , "price" : 8.99 } ,
{ "category" : "fiction" , "author" : "J. R. R. Tolkien" , "title" : "The Lord of the Rings" , "isbn" : "0-395-19395-8" , "price" : 22.99 }
] ,
"bicycle" : { "color" : "red" , "price" : 19.95 }
} ,
"expensive" : 10
}
JsonPath 表达式 结果说明 $.store.book[*].author 或 $..author所有书籍的作者列表 $.store.*显示 store 下所有叶子节点值 $..price递归查找所有价格字段 $..book[0,1] 或 $..book[:2]前两本书 $..book[-2:]最后两本书 $..book[2:]从索引 2 开始的书 $..book[?(@.isbn)]所有拥有 isbn 属性的书 $.store.book[?(@.price < 10)]价格低于 10 的书 $..book[?(@.price <= $['expensive'])]价格低于 expensive 字段的书 $..book[?(@.author =~ /.*REES/i)]作者名符合正则的书 $..*返回所有节点 $..book.length()书籍数量
常用 API 模式 String json = "..." ;
List<String> authors = JsonPath.read(json, "$.store.book[*].author" );
这种方式适合单次解析。如果需要对同一个 JSON 解析多次,不建议重复调用 read,因为每次都会重新解析。此时建议使用 ReadContext 或 WriteContext:
String json = "..." ;
ReadContext ctx = JsonPath.parse(json);
List<String> authorsOfBooksWithISBN = ctx.read("$.store.book[?(@.isbn)].author" );
List<Map<String, Object>> expensiveBooks = JsonPath
.using(configuration)
.parse(json)
.read("$.store.book[?(@.price > 10)]" , List.class);
返回值与类型转换 read 后的返回值会自动转型到指定类型。对于明确定义的表达式,应指定对应类型;对于含糊表达式(包含 ..、?[...] 等),通常应使用数组接收。如需转换成具体类型,可通过 configuration 配置 mappingProvider:
String json = "{\"date_as_long\" : 1411455611975}" ;
Date date = JsonPath.parse(json).read("$['date_as_long']" , Date.class);
Book book = JsonPath.parse(json).read("$.store.book[0]" , Book.class);
自定义映射提供者 JsonPath 支持 SPI 扩展反序列化器。默认使用 JsonSmartMappingProvider,它注册了基本数据类型的转换逻辑。若需切换 Provider(例如使用 Jackson),可配置如下:
Configuration.setDefaults(new Configuration .Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonProvider ();
private final MappingProvider mappingProvider = new JacksonMappingProvider ();
@Override public JsonProvider jsonProvider () { return jsonProvider; }
@Override public MappingProvider mappingProvider () { return mappingProvider; }
@Override public Set<Option> options () { return EnumSet.noneOf(Option.class); }
});
断言谓词实现
1. Inline Predicates 直接在表达式中使用 ?[<@expression>]:
List<Map<String, Object>> books = JsonPath.parse(json)
.read("$.store.book[?(@.price < 10)]" );
2. Filter API import static com.jayway.jsonpath.JsonPath.parse;
import static com.jayway.jsonpath.Criteria.where;
import static com.jayway.jsonpath.Filter.filter;
Filter cheapFictionFilter = filter(
where("category" ).is("fiction" ).and("price" ).lte(10D )
);
List<Map<String, Object>> books = parse(json).read("$.store.book[?]" , cheapFictionFilter);
Filter fooOrBar = filter(where("foo" ).exists(true )).or(where("bar" ).exists(true ));
注意:表达式中必须有占位符 ?,多个占位符会按顺序替换。
3. 自定义 Predicate Predicate booksWithISBN = new Predicate () {
@Override
public boolean apply (PredicateContext ctx) {
return ctx.item(Map.class).containsKey("isbn" );
}
};
List<Map<String, Object>> books = reader.read("$.store.book[?].isbn" , List.class, booksWithISBN);
获取路径列表 有时需要获取匹配到的完整路径而非值,可使用 AS_PATH_LIST 选项:
Configuration conf = Configuration.builder()
.options(Option.AS_PATH_LIST)
.build();
List<String> pathList = using(conf).parse(json).read("$..author" );
配置选项详解
DEFAULT_PATH_LEAF_TO_NULL 检索不到时返回 null 而不是抛出异常。默认行为是抛出 PathNotFoundException。
Configuration conf2 = conf.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
String gender1 = JsonPath.using(conf2).parse(json).read("$[1]['gender']" );
ALWAYS_RETURN_LIST 总是返回 List,即使结果是单个非 List 类型也会被包装。
SUPPRESS_EXCEPTIONS 不抛出异常。开启 ALWAYS_RETURN_LIST 时返回空 List,否则返回 null。
AS_PATH_LIST
REQUIRE_PROPERTIES
缓存机制 每次 read 都会尝试获取缓存以提高性能,但默认未启用。JsonPath 2.1.0+ 提供了新的 SPI 缓存实现:
NOOPCache: 无缓存
LRUCache: 默认实现,线程安全
CacheProvider.setCache(new Cache () {
private Map<String, JsonPath> map = new HashMap <>();
@Override public JsonPath get (String key) { return map.get(key); }
@Override public void put (String key, JsonPath jsonPath) { map.put(key, jsonPath); }
});
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online