豪爽的花生 · VS2017下创建C++动态库导出符合并完成 ...· 7 月前 · |
小胡子的匕首 · Oracle 存储过程中 IF ...· 1 年前 · |
时尚的西红柿 · Android 缓存目录 ...· 1 年前 · |
帅气的酱牛肉 · HarmonyOS后台代理提醒(ArkTS)· 1 年前 · |
不羁的肉夹馍 · python - Trying to ...· 1 年前 · |
JsonPath是用来提取json文档中内容的,跟xpath用来提取html或xml中内容一样,是一种路径表达式。
而这里说的是Java语言中的json-path包,其他语言如JavaScript也是也可以使用JsonPath的,但是相关解析的第三包不一样,下面所用的包是Java语言支持的,但json路径表达式的语法是通用的。
如果使用Gson等进行解析json,提取里面的个别值,代码会很多比较麻烦,而JsonPath只需要一个简单的路径表达式就可以提取到值,代码简洁。
一般情况下,做爬虫的对提取json中内容的需求比较大。
它的官网地址: JsonPath
它的maven坐标如下:
< dependency > < groupId > com.jayway.jsonpath </ groupId > < artifactId > json-path </ artifactId > < version > 2.6.0 </ version > </ dependency >
如果报错
Caused by: java.lang.NoClassDefFoundError: net/minidev/json/writer/JsonReaderI
则需要加上如下依赖:
JsonPath中的根成员对象是
$
。JsonPath获取数据有两种表示方法:
$.store.book[0].title
$['store']['book'][0]['title']
入门示例如下:
public class Test {
@Test
public void hello() {
String json = "{\"msg\":\"hello world\"}";
String msg = JsonPath.read(json, "$.msg");
System.out.println(msg);
用于测试的json字符串如下:
"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支持的操作符如下表:
操作 说明 $
查询根元素。这将启动所有路径表达式。 @
当前节点由过滤谓词处理。 *
通配符,必要时可用任何地方的名称或数字。 ..
深层扫描。必要时在任何地方可以使用名称。 .<name>
点,表示子节点 ['<name>' (, '<name>')]
括号表示子项 [<number> (, <number>)]
数组索引或索引,索引从0开始 [start:end]
数组切片操作 [?(<expression>)]
过滤表达式。 表达式必须求值为一个布尔值。
示例如下:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 获取json中store下book下的所有author值
List<String> authors = JsonPath.read(json, "$.store.book[*].author");
System.out.println(authors);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
@Test
public void test02() {
// 获取所有json中所有author的值
List<String> authors = JsonPath.read(json, "$..author");
System.out.println(authors);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
@Test
public void test03() {
// 获取所有的书籍和自行车
Object obj = JsonPath.read(json, "$.store.*");
System.out.println(obj);// [[{"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}],{"color":"red","price":19.95}]
@Test
public void test04() {
// 获取json中store下所有price的值
List<Float> prices = JsonPath.read(json, "$.store..price");
System.out.println(prices);// [8.95,12.99,8.99,22.99,19.95]
@Test
public void test05() {
// 获取json中book数组的第3本书,注意索引是从0开始的,但也需要注意返回的是一个数组而非一个Map集合
List<Map<String, Object>> book = JsonPath.read(json, "$..book[2]");
System.out.println(book);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
@Test
public void test06() {
// 获取倒数第二本书,即支持倒序索引,从-1开始
List<Map<String, Object>> book = JsonPath.read(json, "$..book[-2]");
System.out.println(book);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
@Test
public void test07() {
// 获取前两本书,即在数组中索引为0和1的两本书
List<Map<String, Object>> books = JsonPath.read(json, "$..book[0,1]");
System.out.println(books);// [{"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}]
@Test
public void test08() {
// 获取从索引0(包括)到索引2(排除)的所有图书,即[0,2)这样的关系
List<Map<String, Object>> books = JsonPath.read(json, "$..book[:2]");
System.out.println(books);// [{"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}]
@Test
public void test09() {
// 获取从索引1(包括)到索引2(排除)的所有图书,即[1,2)这样的关系
List<Map<String, Object>> books = JsonPath.read(json, "$..book[1:2]");
System.out.println(books);// [{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]
@Test
public void test10() {
// 获取json中book数组的最后两个值
List<Map<String, Object>> books = JsonPath.read(json, "$..book[-2:]");
System.out.println(books);// [{"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}]
@Test
public void test11() {
// 获取json中book数组的第3个到最后一个的区间值,包括最后一个
List<Map<String, Object>> books = JsonPath.read(json, "$..book[2:]");
System.out.println(books);// [{"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}]
@Test
public void test12() {
// 获取json中book数组中包含isbn的所有值
List<Map<String, Object>> books = JsonPath.read(json, "$..book[?(@.isbn)]");
System.out.println(books);// [{"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}]
@Test
public void test13() {
// 获取json中book数组中price<10的所有值
List<Map<String, Object>> books = JsonPath.read(json, "$..book[?(@.price < 10)]");
System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
JsonPath还支持一些函数,函数可以在路径的尾部调用,函数的输出是路径表达式的输出,该函数的输出是由函数本身所决定的。如下表:
函数 描述 输出 min() 提供数字数组的最小值 Double max() 提供数字数组的最大值 Double avg() 提供数字数组的平均值 Double stddev() 提供数字数组的标准偏差值 Double length() 提供数组的长度 Integer sum() 提供数组中所有原生的总和 Double keys() 提供所有的键名 Set concat(X) Provides a concatinated version of the path output with a new item like input append(X) 向路径表达式的输出数组新增一项 like input
示例如下:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 获取有几本书
int length = JsonPath.read(json, "$..book.length()");
System.out.println(length);
@Test
public void test02() {
// 获取最小书价
double min = JsonPath.read(json, "$..book..price.min()");
System.out.println(min);// 8.95
@Test
public void test03() {
// 获取最大书价
double max = JsonPath.read(json, "$..book..price.max()");
System.out.println(max);// 22.99
@Test
public void test04() {
// 获取平均书价
double avg = JsonPath.read(json, "$..book..price.avg()");
System.out.println(avg);// 13.48
@Test
public void test05() {
// 获取书价的标准偏差值,这是统计学上的概念,几乎用不到
Object obj = JsonPath.read(json, "$..book..price.stddev()");
System.out.println(obj);
@Test
public void test06() {
// 获取所有书的总价
double sum = JsonPath.read(json, "$..book..price.sum()");
System.out.println(sum);// 53.92
@Test
public void test07() {
// 获取第二本书所有的属性键名
Set<String> set = JsonPath.read(json, "$.store.book[2].keys()");
System.out.println(set);// [category, author, title, isbn, price]
过滤器运算符
过滤器是用于筛选数组的逻辑表达式。一个典型的过滤器将是[?(@.age > 18)]
,其中@
表示正在处理的当前项。 可以使用逻辑运算符&&
和||
(分别表示与
和或
)创建更复杂的过滤器。 字符串文字必须用单引号或双引号括起来([?(@.color == 'blue')]
或者 [?(@.color == "blue")]
).
操作符 描述 ==
left等于right(注意1不等于’1’) !=
不等于 <
小于 <=
小于等于 >
大于 >=
大于等于 =~
匹配正则表达式,如[?(@.name =~ /foo.*?/i)]
in
左边存在于右边,如[?(@.size in ['S', 'M'])]
nin
左边不存在于右边 subsetof
左边是一个右边的子集合,如[?(@.sizes subsetof ['S','M','L'])]
anyof
左边的集合与右边的集合相交,如[?(@.sizes anyof ['M','L'])]
noneof
左右的集合与右边的集合不相交,如[?(@.sizes noneof ['M','L'])]
size
左边(数组或字符串)长度应该匹配右边的数值 empty
左边(数组或字符串)为空
示例如下:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 查找category等于"fiction"的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category=='fiction')]");
System.out.println(books);// [{"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}]
@Test
public void test02() {
// 查找category不等于"fiction"的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category!='fiction')]");
System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95}]
@Test
public void test03() {
// 查找price小于10的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.price<10)]");
System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
@Test
public void test04() {
// 查找price大于10的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.price>10)]");
System.out.println(books);// [{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
@Test
public void test05() {
// 利用正则表达式匹配title中包含"of the"的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.title =~ /.*of the.*/i)]");
System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]
@Test
public void test06() {
// 查询category存在于["reference","abc"]的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category in ['reference','abc'])]");
System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95}]
@Test
public void test07() {
// 查询category不存在于["reference","abc"]的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.category nin ['reference','abc'])]");
System.out.println(books);// [{"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}]
@Test
public void test08() {
// ['S','M']是['S','M','L']的子集,所以被匹配了
String json = "{\"sizes\":[\"S\",\"M\"]}";
Object result = JsonPath.read(json, "$[?(@.sizes subsetof ['S','M','L'])]");
System.out.println(result);// [{"sizes":["S","M"]}]
@Test
public void test09() {
// ['S','M']与['M','L']发生相交,其中'M'是相交的值
String json = "{\"sizes\":[\"S\",\"M\"]}";
Object result = JsonPath.read(json, "$[?(@.sizes anyof ['M','L'])]");
System.out.println(result);// [{"sizes":["S","M"]}]
@Test
public void test10() {
// ['S','X']与['M','L']不发生相交,所以被匹配了
String json = "{\"sizes\":[\"S\",\"X\"]}";
Object result = JsonPath.read(json, "$[?(@.sizes noneof ['M','L'])]");
System.out.println(result);
@Test
public void test11() {
// 匹配title只有9个字符的书籍
List<Map<String, Object>> books = JsonPath.read(json, "$.store.book[?(@.title size 9)]");
System.out.println(books);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
上面的语法已经够我们日常使用了,下面是JsonPath的一些扩展使用。
我们上面使用的都是JsonPath.read()
方法读取内容,如果只读取一次那么是可行的,如果想要读取多次,那么这不是一个好的方法,因为该方法每次读取都需要解析整个json文档,耗费性能。
所以如果我们需要读取多个路径,那么我们可以选择先解析整个文档,再解析路径读取内容。
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 通过解析多次文档读取多个路径
long start1 = System.currentTimeMillis();// 可以查看它们花费的时间
String author0 = JsonPath.read(json, "$.store.book[0].author");
String author1 = JsonPath.read(json, "$.store.book[1].author");
long end1 = System.currentTimeMillis();
System.out.println(author0 + ", " + author1 + ", " + (end1 - start1));// Nigel Rees, Evelyn Waugh, 1218
// 通过解析一次文档读取多个路径【推荐】
long start2 = System.currentTimeMillis();
Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
String author2 = JsonPath.read(document, "$.store.book[0].author");
String author3 = JsonPath.read(document, "$.store.book[1].author");
long end2 = System.currentTimeMillis();
System.out.println(author2 + ", " + author3 + ", " + (end2 - start2));// Nigel Rees, Evelyn Waugh, 1
核心代码就是:
String json="...";
Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
String author2 = JsonPath.read(document, "$.store.book[0].author");
还可以使用下面这种API,链式配置很灵活:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 通过阅读上下文来解析路径
ReadContext context = JsonPath.parse(json);
List<String> authors = context.read("$.store.book..author");
System.out.println(authors);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
// 或者链式调用
List list = JsonPath
.using(Configuration.defaultConfiguration())
.parse(json)
.read("$.store.book..author", List.class);
System.out.println(list);// ["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]
返回结果类型
在使用JsonPath时,要明确知道路径的结果是什么类型,JsonPath会尝试转换为所期待的类型,如:
// 抛出 java.lang.ClassCastException 异常
List<String> list = JsonPath.parse(json).read("$.store.book[0].author")// 实际是返回的是一个字符串,所以用List来接收不合适,无法强制类型转换
// 正常
String author = JsonPath.parse(json).read("$.store.book[0].author")
在评估路径时,您需要了解路径何时确定的概念。如果路径包含以下内容,则该路径是不确定的:
..
:深层扫描操作?(<expression>)
:表达式[<number>, <number> (, <number>)]
:多个数组索引
不确定的路径总数返回一个列表,可由List接收。
返回结果映射
- 简单对象映射
默认情况下,MappingProvider SPI提供了一个简单的对象映射器。 这允许您指定所需的返回类型,MappingProvider将尝试执行映射。如将Long类型的时间戳转换成Date类型的日期:
public class JsonPathTest {
@Test
public void test01() {
String json = "{\"timestamp\":1641519588137}";
Date date = JsonPath.parse(json).read("$.timestamp", Date.class);
System.out.println(date);// Fri Jan 07 09:39:48 CST 2022
- POJO对象映射
如果是简单的实体类映射,如Book
,如下即可:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
Book book = JsonPath.parse(json).read("$.store.book[0]", Book.class);
System.out.println(book);// Book{category='reference', author='Nigel Rees', title='Sayings of the Century', isbin='null', price=8.95}
class Book {
private String category;
private String author;
private String title;
private String isbn;
private float price;
public Book() {
public Book(String category, String author, String title, String isbn, float price) {
this.category = category;
this.author = author;
this.title = title;
this.isbn = isbn;
this.price = price;
public String getCategory() {
return category;
public void setCategory(String category) {
this.category = category;
public String getAuthor() {
return author;
public void setAuthor(String author) {
this.author = author;
public String getTitle() {
return title;
public void setTitle(String title) {
this.title = title;
public String getIsbn() {
return isbn;
public void setIsbn(String isbn) {
this.isbn = isbn;
public float getPrice() {
return price;
public void setPrice(float price) {
this.price = price;
@Override
public String toString() {
return "Book{" +
"category='" + category + '\'' +
", author='" + author + '\'' +
", title='" + title + '\'' +
", isbin='" + isbn + '\'' +
", price=" + price +
'}';
但如果是更复杂的情况,如List<Book>
,则可以考虑将JsonPath配置为使用JacksonMappingProvider或GsonMappingProvider,这样就能让JsonPath输出直接映射到POJO中。
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 1.进行默认配置
Configuration.setDefaults(new Configuration.Defaults() {
// 注意,这里创建的是GsonJsonProvider和GsonMappingProvider,但需要导入Gson包
// 还可以使用JacksonJsonProvider和JacksonMappingProvider,也需要导入jackson包
private final JsonProvider jsonProvider = new GsonJsonProvider();
private final MappingProvider mappingProvider = new GsonMappingProvider();
@Override
public JsonProvider jsonProvider() {
return jsonProvider;
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
@Override
public MappingProvider mappingProvider() {
return mappingProvider;
});
// 2.设置泛型,List<Book>泛型是无法直接在read()方法中传入的,所以需要在TypeRef<>中设置泛型
TypeRef<List<Book>> typeRef = new TypeRef<List<Book>>() {};
// 3.调用read()方法传入路径表达式和泛型并读取数据
List<Book> books = JsonPath.parse(json).read("$.store.book.*", typeRef);
// 4.打印结果
for (Book book : books) {
System.out.println(book);
// Book{category='reference', author='Nigel Rees', title='Sayings of the Century', isbin='null', price=8.95}
// Book{category='fiction', author='Evelyn Waugh', title='Sword of Honour', isbin='null', price=12.99}
// Book{category='fiction', author='Herman Melville', title='Moby Dick', isbin='0-553-21311-3', price=8.99}
// Book{category='fiction', author='J. R. R. Tolkien', title='The Lord of the Rings', isbin='0-395-19395-8', price=22.99}
class Book {
private String category;
private String author;
private String title;
private String isbn;
private float price;
public Book() {
public Book(String category, String author, String title, String isbn, float price) {
this.category = category;
this.author = author;
this.title = title;
this.isbn = isbn;
this.price = price;
public String getCategory() {
return category;
public void setCategory(String category) {
this.category = category;
public String getAuthor() {
return author;
public void setAuthor(String author) {
this.author = author;
public String getTitle() {
return title;
public void setTitle(String title) {
this.title = title;
public String getIsbn() {
return isbn;
public void setIsbn(String isbn) {
this.isbn = isbn;
public float getPrice() {
return price;
public void setPrice(float price) {
this.price = price;
@Override
public String toString() {
return "Book{" +
"category='" + category + '\'' +
", author='" + author + '\'' +
", title='" + title + '\'' +
", isbin='" + isbn + '\'' +
", price=" + price +
'}';
在JsonPath中创建过滤器谓词有三种不同的方法。
内联谓词就是在路径中直接定义的谓词。如:
List<Map<String, Object>> books = JsonPath.parse(json).read("$.store.book[?(@.price < 10)]");
其中[?(@.price < 10)]
就是内联谓词,要求过滤书籍价格小于10的书。
还可以使用$$
和||
结合使用多个谓词,即多个过滤条件呈现“与”和“或”的关系,如[?(@.price < 10 && @.category == 'fiction')]
表示过滤价格小于10并且分类为fiction的书籍(多个条件同时满足)、[?(@.category == 'reference' || @.price > 10)]
表示过滤分类为reference或者价格大于10的书籍(只要满足任一条件即可)。
还有一个!
表示“非”,如[?(!(@.price < 10 && @.category == 'fiction'))]
表示价格既不小于10分类也不是fiction的书籍。
谓词可以使用Filter API构建,如下所示:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 声明谓词过滤器
Filter bookFilter = Filter.filter(
// 类似于SQL语句中的条件,即category=='fiction' && price<=10
Criteria.where("category").is("fiction").and("price").lte(10)
// 调用read方法传入路径表达式和谓词过滤器
List<Map<String, Object>> books = JsonPath.parse(json).read("$.store.book[?]", bookFilter);
System.out.println(books);// [{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]
- 路径表达式
$.store.book[?]
中使用了占位符?
来表示路径中的过滤器。 - 当提供多个过滤器时,它们按照占位符数量与提供的过滤器数量相匹配的顺序应用。
- 可以在一个过滤器操作
[?,?]
中指定多个谓词占位符,这两个谓词都必须匹配。 - 过滤器可以使用
.or()
、.and()
、.exists()
来表示“或”、“与”、“非”。
自定义谓词
还可以实现自己的谓词,进行更复杂的过滤。
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 自定义谓词
Predicate booksPredicate = new Predicate() {
@Override
public boolean apply(PredicateContext context) {
// 要求过滤书籍作者的名字刚好是10个字符
return context.item(Map.class).get("author").toString().length() == 10;
// 调用read方法传入路径表达式和自定义谓词
List<Map<String, Object>> books = JsonPath.parse(json).read("$.store.book[?]", List.class, booksPredicate);
System.out.println(books);// [{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95}]
路径 vs 值
默认情况下,JsonPath是返回值的,但也可以要求它返回匹配元素的完整路径。如下:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 进行配置,要求返回路径
Configuration conf = Configuration.builder().options(Option.AS_PATH_LIST).build();
// 传入配置读取路径
List<String> pathList = JsonPath.using(conf).parse(json).read("$..author");
System.out.println(pathList);// ["$['store']['book'][0]['author']","$['store']['book'][1]['author']","$['store']['book'][2]['author']","$['store']['book'][3]['author']"]
选项创建配置时,有几个可以改变默认行为的选项标志。
DEFAULT_PATH_LEAF_TO_NULL
此选项使JsonPath对于缺少的叶子返回null,如下的json:
"name" : "john",
"gender" : "male"
"name" : "ben"
获取第二个对象中的gender
,如果按照默认配置项则会抛出异常,我们希望它不存在时能返回null,那么可以设置DEFAULT_PATH_LEAF_TO_NULL
。
public class JsonPathTest {
@Test
public void test01() {
String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";
Configuration conf = Configuration.defaultConfiguration();
// 正常
String gender0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");
// 异常 PathNotFoundException thrown
String gender1 = JsonPath.using(conf).parse(json).read("$[1]['gender']");// com.jayway.jsonpath.PathNotFoundException: No results for path: $[1]['gender']
System.out.println(gender0 + ", " + gender1);
@Test
public void test02() {
String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";
Configuration conf2 = Configuration.defaultConfiguration().addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
// 正常
String gender0 = JsonPath.using(conf2).parse(json).read("$[0]['gender']");
// 正常 (返回 null)
String gender1 = JsonPath.using(conf2).parse(json).read("$[1]['gender']");
System.out.println(gender0 + ", " + gender1);// male, null
ALWAYS_RETURN_LIST
此选项将JsonPath配置为返回列表,即使路径是确定的。
如$[0]['gender']
的结果是一个字符串,我们可以使用String
来接收它,但如果我们想要使用List<String>
来接收这单个字符串,那么就需要配置ALWAYS_RETURN_LIST
选项。
public class JsonPathTest {
@Test
public void test01() {
String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";
Configuration conf = Configuration.defaultConfiguration();
List<String> genders0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");// java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
System.out.println(genders0);
@Test
public void test02() {
String json = "[{\"name\":\"john\",\"gender\":\"male\"},{\"name\":\"ben\"}]";
Configuration conf = Configuration.defaultConfiguration().addOptions(Option.ALWAYS_RETURN_LIST);// 设置总是返回列表
List<String> genders0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");
System.out.println(genders0);// ["male"]
SUPPRESS_EXCEPTIONS
该选项确保不会从路径评估传播异常。 遵循这些简单的规则:
- 如果选项ALWAYS_RETURN_LIST存在,将返回一个空列表
- 如果选项ALWAYS_RETURN_LIST不存在返回null
JsonProvider SPI
JsonPath附带了五个不同的JsonProvider:
JsonSmartJsonProvider
(默认)JacksonJsonProvider
JacksonJsonNodeJsonProvider
GsonJsonProvider
JsonOrgJsonProvider
JakartaJsonProvider
只有在初始化应用程序时,才能更改所演示的配置默认值。强烈反对在运行时进行更改,尤其是在多线程应用程序中。
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);
});
注意:JacksonJsonProvider需要com.fasterxml.jackson.core:jackson-databind:2.4.5
,GsonJsonProvider需要在您的类路径上使用com.google.code.gson:gson:2.3.1
,即需要导入相关的jar包才能使用。
使用JacksonJsonProvider或GsonJsonProvider可以直接将JsonPath的输出映射到实体类上,如下例:
public class JsonPathTest {
private String json = "{\"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}";
@Test
public void test01() {
// 1.进行默认配置
Configuration.setDefaults(new Configuration.Defaults() {
// 注意,这里创建的是GsonJsonProvider和GsonMappingProvider,但需要导入Gson包
// 还可以使用JacksonJsonProvider和JacksonMappingProvider,也需要导入jackson包
private final JsonProvider jsonProvider = new GsonJsonProvider();
private final MappingProvider mappingProvider = new GsonMappingProvider();
@Override
public JsonProvider jsonProvider() {
return jsonProvider;
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
@Override
public MappingProvider mappingProvider() {
return mappingProvider;
});
// 2.设置泛型,List<Book>泛型是无法直接在read()方法中传入的,所以需要在TypeRef<>中设置泛型
TypeRef<List<Book>> typeRef = new TypeRef<List<Book>>() {};
// 3.调用read()方法传入路径表达式和泛型并读取数据
List<Book> books = JsonPath.parse(json).read("$.store.book.*", typeRef);
// 4.打印结果
for (Book book : books) {
System.out.println(book);
// Book{category='reference', author='Nigel Rees', title='Sayings of the Century', isbin='null', price=8.95}
// Book{category='fiction', author='Evelyn Waugh', title='Sword of Honour', isbin='null', price=12.99}
// Book{category='fiction', author='Herman Melville', title='Moby Dick', isbin='0-553-21311-3', price=8.99}
// Book{category='fiction', author='J. R. R. Tolkien', title='The Lord of the Rings', isbin='0-395-19395-8', price=22.99}
class Book {
private String category;
private String author;
private String title;
private String isbn;
private float price;
public Book() {
public Book(String category, String author, String title, String isbn, float price) {
this.category = category;
this.author = author;
this.title = title;
this.isbn = isbn;
this.price = price;
public String getCategory() {
return category;
public void setCategory(String category) {
this.category = category;
public String getAuthor() {
return author;
public void setAuthor(String author) {
this.author = author;
public String getTitle() {
return title;
public void setTitle(String title) {
this.title = title;
public String getIsbn() {
return isbn;
public void setIsbn(String isbn) {
this.isbn = isbn;
public float getPrice() {
return price;
public void setPrice(float price) {
this.price = price;
@Override
public String toString() {
return "Book{" +
"category='" + category + '\'' +
", author='" + author + '\'' +
", title='" + title + '\'' +
", isbin='" + isbn + '\'' +
", price=" + price +
'}';
封装工具类
针对使用JsonPath来提取json字符串中的内容然后封装到实体类中,可以做一些简单的封装:
package json;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import java.lang.reflect.Field;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
* @author lcl100
* @desc JsonPath工具类
* @date 2022-01-10
public class JsonPathUtil {
* JsonPath配置
private final static Configuration configuration = Configuration.defaultConfiguration().addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
* 根据路径表达式读取json中的内容
* @param json 待读取的json字符串
* @param path JsonPath路径表达式
* @return 读取到的结果
private static Object readPath(String json, String path) {
Object result = null;
try {
result = JsonPath.using(configuration).parse(json).read(path);
} catch (Exception ignored) {
return result;
* 根据json模板字符串提取json中对应内容然后填充到类中对应映射字段,提取实体类
* @param json 待提取的json字符串
* @param jsonPath json模板字符串,存储着实体类属性名与json中对应内容的路径关系
* @param clazz 待映射的实体类
* @param <T> 实体类泛型
* @return 从json字符串中提取了内容后并赋值的实体类对象
* @throws InstantiationException 创建实例对象异常
* @throws IllegalAccessException 字段访问权限异常
public static <T> T getJsonObject(String json, String jsonPath, Class<T> clazz) throws InstantiationException, IllegalAccessException {
// 提取jsonPath这个json字符串中的所有键值对
Map<String, Map<String, String>> arrayMap = new HashMap<>();
Map<String, String> objectMap = new HashMap<>();
// 判断模板字符串是json对象还是json数组
jsonPath = jsonPath.trim();
char firstChar = jsonPath.charAt(0);
boolean isArray = false;
if (firstChar == '[') {
isArray = true;
// 读取json数组中的所有json对象,每个json对象都是一个Map集合,然后放到List中
List<Map<String, String>> mapList = (List<Map<String, String>>) readPath(jsonPath, "$");
for (Map<String, String> map : mapList) {
arrayMap.put(map.getOrDefault("NAME", null), map);
} else if (firstChar == '{') {
isArray = false;
// 读取所有键值对成一个Map集合
objectMap = (Map<String, String>) readPath(jsonPath, "$");
// 获取类的所有字段,依次赋值
T t = clazz.newInstance();
Class<?> tClass = t.getClass();
Field[] fields = tClass.getDeclaredFields();
for (Field field : fields) {
// 根据字段名提取对应的路径表达式,然后根据路径表达式在json中提取值
String name = field.getName();
// 由于模板字符串的不同,提取路径的方式有所不同
String path = isArray ? (arrayMap.getOrDefault(name, null) != null ? arrayMap.get(name).get("PATH") : null) : objectMap.getOrDefault(name, null);
// 根据路径读取值
Object value = readPath(json, path);
// 如果使用的是带有正则表达式的模板字符串则需要额外处理
if (isArray) {
// 进行正则提取
Matcher matcher = Pattern.compile(arrayMap.getOrDefault(name, null).getOrDefault("REGEXP", null)).matcher(String.valueOf(value));
if (matcher.find()) {
value = matcher.group(1);
// 为字段赋值
setField(field, t, value);
return t;
* 根据json模板字符串提取json中对应内容然后填充到类中对应映射字段,提取实体类集合
* @param json 待提取的json字符串
* @param jsonPath json模板字符串,存储着实体类属性名与json中对应内容的路径关系
* @param clazz 待映射的实体类
* @param <T> 实体类泛型
* @return 赋值后的实体类集合
* @throws InstantiationException 创建实例对象异常
* @throws IllegalAccessException 字段访问权限异常
public static <T> List<T> getJsonList(String json, String jsonPath, Class<T> clazz) throws InstantiationException, IllegalAccessException {
List<T> list = new ArrayList<>();
Map<String, Map<String, String>> arrayMap = new HashMap<>();
Map<String, String> objectMap = new HashMap<>();
// 根据是否有"DATA"来判断模板字符串是什么模式
boolean isArray = jsonPath.contains("DATA");
if (isArray) {// 该模式使用了正则表达式
// 直接是一个数组,包含多个json对象,即包含多个Map集合
List<Map<String, String>> mapList = (List<Map<String, String>>) readPath(jsonPath, "$.DATA");
for (int i = 0; i < mapList.size(); i++) {
Map<String, String> map = mapList.get(i);
String name = map.get("NAME");
String path = map.get("PATH");
if (name != null && !"".equals(name.trim()) && path != null && !"".equals(path.trim())) {
arrayMap.put(name, map);
} else {// 该模式未使用正则表达式
// 直接是一个Map集合,包括所有的键值对
objectMap = (Map<String, String>) readPath(jsonPath, "$");
// 计算ROOT_LIST所表示路径在json字符串中代表的数组的长度
String rootPath = (String) readPath(jsonPath, "$.ROOT_LIST");
int length = (int) readPath(json, rootPath + ".length()");
for (int j = 0; j < length; j++) {
// 创建实体类对象
T t = clazz.newInstance();
Class<?> tClass = t.getClass();
// 获取所有声明的字段
Field[] fields = tClass.getDeclaredFields();
for (Field field : fields) {
// 字段名
String fieldName = field.getName();
// 待赋给字段的值
Object value;
if (isArray) {
// 过滤掉不需要提取的字段
if (arrayMap.getOrDefault(fieldName, null) == null) {
continue;
// 从json中读取指定路径的值
value = readPath(json, rootPath + "[" + j + "]" + arrayMap.getOrDefault(fieldName, null).get("PATH"));
// 需要进行正则处理
Matcher matcher = Pattern.compile(arrayMap.getOrDefault(fieldName, null).getOrDefault("REGEXP", null)).matcher(String.valueOf(value));
if (matcher.find()) {
value = matcher.group(1);
} else {
// 过滤掉不需要提取的字段
if (objectMap.getOrDefault(fieldName, null) == null) {
continue;
// 从json中读取指定路径的值
value = readPath(json, rootPath + "[" + j + "]" + objectMap.getOrDefault(fieldName, null));
// 为字段赋值
setField(field, t, value);
list.add(t);
return list;
* 根据字段类型为实例对象上的字段进行赋值
* @param field 待赋值的字段
* @param t 实例对象
* @param value 待赋予的值
* @throws IllegalAccessException 字段访问权限异常
private static void setField(Field field, Object t, Object value) throws IllegalAccessException {
String typeName = field.getType().getTypeName();
field.setAccessible(true);
if (typeName.endsWith("String")) {
field.set(t, String.valueOf(value));
} else if (typeName.endsWith("byte")) {
byte result = 0;
try {
result = Byte.parseByte(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Byte")) {
Byte result = null;
try {
result = Byte.valueOf(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("short")) {
short result = 0;
try {
result = Short.parseShort(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Short")) {
Short result = null;
try {
result = Short.valueOf(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("int")) {
int result = 0;
try {
result = Integer.parseInt(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Integer")) {
Integer result = null;
try {
result = Integer.valueOf(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("long")) {
long result = 0L;
try {
result = Long.parseLong(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Long")) {
Long result = null;
try {
result = Long.valueOf(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("float")) {
float result = 0F;
try {
result = Float.parseFloat(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Float")) {
Float result = null;
try {
result = Float.valueOf(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("double")) {
double result = 0;
try {
result = Double.parseDouble(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Double")) {
Double result = null;
try {
result = Double.valueOf(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("boolean")) {
boolean result = false;
try {
result = Boolean.parseBoolean(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Boolean")) {
Boolean result = null;
try {
result = Boolean.valueOf(value.toString());
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("char")) {
char result = '\u0000';
try {
result = value.toString().charAt(0);
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Character")) {
Character result = null;
try {
result = value.toString().charAt(0);
} catch (Exception ignored) {
field.set(t, result);
} else if (typeName.endsWith("Date")) {
Date result = null;
// 暂时只能处理时间戳的日期
try {
Matcher timestampMatcher = Pattern.compile("1[\\d]{9}").matcher(value.toString());
if (timestampMatcher.find()) {
result = new Date(Long.parseLong(value.toString()));
} catch (Exception ignored) {
field.set(t, result);
} else {
System.out.println("无法转换的字段类型: " + typeName);
测试类如下:
public class JsonPathUtilTest {
private final String json = "{\"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}";
@Test
public void testGetJsonObject() throws InstantiationException, IllegalAccessException {
// 注意,jsonPath模板表达式中,键名为实体类中的属性名;键值为在json字符串中的完整路径
// 第一种形式的模板字符串
String jsonPath1 = "{\n" +
" \"category\": \"$.store.book[0].category\",\n" +
" \"author\": \"$.store.book[0].author\",\n" +
" \"title\": \"$.store.book[0].title\",\n" +
" \"isbn\": \"$.store.book[0].isbn\",\n" +
" \"price\": \"$.store.book[0].price\"\n" +
"}";
Book book1 = JsonPathUtil.getJsonObject(json, jsonPath1, Book.class);
System.out.println(book1);
// 第二种形式的模板字符串
String jsonPath2 = "[\n" +
" {\n" +
" \"NAME\": \"category\",\n" +
" \"PATH\": \"$.store.book[0].category\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"author\",\n" +
" \"PATH\": \"$.store.book[0].author\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"title\",\n" +
" \"PATH\": \"$.store.book[0].title\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"isbn\",\n" +
" \"PATH\": \"$.store.book[0].isbn\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"price\",\n" +
" \"PATH\": \"$.store.book[0].price\",\n" +
" \"REGEXP\": \"(\\\\d+\\\\.\\\\d+)\"\n" +
" }\n" +
"]";
Book book2 = JsonPathUtil.getJsonObject(json, jsonPath1, Book.class);
System.out.println(book2);
@Test
public void testGetJsonList() throws InstantiationException, IllegalAccessException {
// 注意,ROOT_LIST为必选字段,表示列表的根路径
// 注意,jsonPath模板表达式中,键名为实体类中的属性名;键值为在json字符串中的相对路径(相对列表的根路径而言)
// 第一种形式的模板字符串
String jsonPath1 = "{\n" +
" \"ROOT_LIST\": \"$.store.book\",\n" +
" \"category\": \".category\",\n" +
" \"author\": \".author\",\n" +
" \"title\": \".title\",\n" +
" \"isbn\": \".isbn\",\n" +
" \"price\": \".price\"\n" +
"}";
List<Book> bookList1 = JsonPathUtil.getJsonList(json, jsonPath1, Book.class);
for (Book book : bookList1) {
System.out.println(book);
// 第二种形式的模板字符串
String jsonPath2 = "{\n" +
" \"ROOT_LIST\": \"$.store.book\",\n" +
" \"DATA\": [\n" +
" {\n" +
" \"NAME\": \"category\",\n" +
" \"PATH\": \".category\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"author\",\n" +
" \"PATH\": \".author\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"title\",\n" +
" \"PATH\": \".title\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"isbn\",\n" +
" \"PATH\": \".isbn\",\n" +
" \"REGEXP\": \"(.*)\"\n" +
" },\n" +
" {\n" +
" \"NAME\": \"price\",\n" +
" \"PATH\": \".price\",\n" +
" \"REGEXP\": \"(\\\\d+\\\\.\\\\d+)\"\n" +
" }\n" +
" ]\n" +
"}";
List<Book> bookList2 = JsonPathUtil.getJsonList(json, jsonPath2, Book.class);
for (Book book : bookList2) {
System.out.println(book);
在线JsonPath测试
可以帮助我们快速判断jsonpath写得是否正确,结果是否是我们期望的结果,而不需要写代码去验证。
介绍fastjson 1.2.0之后的版本支持jsonpath。,可以在java框架中当作json对象查询语言(oql)来使用。常用apipublic class jsonpath {// 求值,静态方法public static object eval(object rootobject, string path);// 求值,静态方法,按需计算,性能更好public static object...
在上面的代码中,$.friends表示JSON根元素中的friends字段,[?(@.age > 30)]表示过滤条件,用于过滤年龄大于30的朋友,name表示要获取的字段名。这里的JsonPath.read()方法返回一个字符串列表,包含匹配条件的所有朋友的名字。在上面的代码中,我们使用$.name路径来获取name字段的值,该路径表示JSON根元素中的name字段。除了读取元素值之外,json-path库还支持一些其他的操作,如过滤、映射、排序等。我们可以使用json-path库来获取其中的某些元素。
I have JSON as a string and a JSONPath as a string. I'd like to query the JSON with the JSON path, getting the resulting JSON as a string.I gather that Jayway's json-path is the standard. The online A...
<dependency>
<groupId>net.minidev</groupId>
<artifactId>asm</artifactId>
<...
背景在一些特殊场景中,可能 一串json有几个甚至上万个节点,那么要去获取里面某一个节点或者说设置某个json指定key的值,那就非常麻烦了,一般我们是通过递归来进行获取,获取后还需要再通过递归进行遍历设置值,所以相当来说非常麻烦。是否有已有现成的工具进行设置呢?注:使用当先请跳转到:注意点进行了解性能问题。jsonPath介绍官网:https://goessner.ne...
public class JSONPath {
// 求值,静态方法
public static Object eval(Object rootObject, String path);
// 计算S...
https://github.com/itguang/gitbook-smile/blob/master/springboot-fastjson/fastjson%E4%B9%8BJSONPath%E4%BD%BF%E7%94%A8.md
1. JSONPath介绍
官网地址: https://github.com/alibaba/fastjson/wiki/JSONPath
fastjson...
Tip注意JSONObject初始化里面记得newLinkedHashMap(),不然会有put进去的数据与输出的数据顺序不一致问题,详情见--->一周工作结束了,这周不太顺利.....周末学习学习,任重而道远......需要的格式(不是上文的对应,只是一个例子)要求被处理的Json文件数据(部分)......
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerAdapter' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet...
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>
修改指定字段:
测试数据文件
"visitPlanList".
用来解析多层嵌套的json数据;JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具.
JsonPath有许多编程语言,如Javascript、Python、PHP、Java等
JsonPath提供的json解析非常强大,它提供了类似正则表达式的语法,基本上可以满足所有你想要获得的json内容。
JSONPathGitHub:https://github.com/json-path/JsonPath
时尚的西红柿 · Android 缓存目录 Context.getExternalFilesDir()和Context.getExternalCacheDir()方法 - 赵彦军 - 博客园 1 年前 |
帅气的酱牛肉 · HarmonyOS后台代理提醒(ArkTS) 1 年前 |