文章目录
- 一、快速入门
- 1.1 Json Path 介绍
- 1.2 引入依赖
- 二、基本使用
- 2.1 基本用法
- 2.2 基本语法
- 2.3 函数语法
- 2.4 筛选语法
- 三、高级用法
- 3.1 动态筛选
- 3.2 多条件筛选
- 3.3 嵌套查询
- 四、API
- 4.1 示例
- 2.2 常用方法
- 2.3 类型转换
- 四、小结
一、快速入门
1.1 Json Path 介绍
正如XPath对XML的解析一样,JSONPath的定义是基于fastjson的json路径解析,对JSON文档的一种解析工具。通过JSONPath可以轻松的对JSON文档获取指定“路径”的数据,在非常复杂的json结构中,对于一些获取和判断操作,不需要层层的去get,可以通过简洁的JsonPath表达式精准找到需要的部分。
1.2 引入依赖
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>x.y.z</version>
</dependency>
- JSONPath在线验证:https://www.jsonpath.cn/
二、基本使用
2.1 基本用法
根据需要解析的路径,使用JsonPath类的静态方法read解析json字符串,并使用read方法返回的Object进行数据获取
String jsonStr = "{'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}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
System.out.println("所有author节点:" + JSONPath.read(jsonStr, "$..author"));
如果是json格式的字符串,则先解析为JSONObject,然后就能直接使用JSONPath.eval了。
String jsonStr = "{'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}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
// 先解析JSON数据
JSONObject jsonObject = JSON.parseObject(jsonStr);
System.out.println("\n Book数目:" + JSONPath.eval(jsonObject, "$.store.book.size()"));
System.out.println("第一本书title:" + JSONPath.eval(jsonObject, "$.store.book[0].title"));
System.out.println("price大于10元的book:" + JSONPath.eval(jsonObject, "$.store.book[price > 10]"));
System.out.println("price大于10元的title:" + JSONPath.eval(jsonObject, "$.store.book[price > 10][0].title"));
System.out.println("bicycle的所有属性值" + JSONPath.eval(jsonObject, "$.store.bicycle.*"));
System.out.println("bicycle的color和price属性值" + JSONPath.eval(jsonObject, "$.store.bicycle['color','price']"));
2.2 基本语法
Json Path的语法相对简单,它采用开发语言友好的表达式形式,如下所示。
JSONPath | 描述 |
---|---|
$ | 文档的根对象,所有路径表达式的开始 |
@ | 文档当前节点对象,类似于java 中的 this 字段 |
. | 子节点,例如$.name |
[num] | 数组访问,其余num 是数字,可以是负数。例如$[0].leader.departments[-1].name |
[‘key’] | 属性访问。例如$[‘name’] |
[‘key0’,‘key1’] | 多个属性访问。例如$[‘id’,‘name’] |
[num0,num1,num2] | 数组多个元素访问,其余num 是数字,可以是负数,返回数组中的多个元素。 例如$[0,1,-2,5] |
… | 可以理解为递归搜索,递归匹配所有子元素。例如$…name |
* | 通配符,适用于任何地方,例如$.leader.* |
[start:end] | 数组范围访问,其中start、end 是开始、结束的下标,可以是负数,返回数组中的多个元素。 |
[?(expression)] | 过滤器表达式,必须返回一个布尔值,例如$.departs[?(name)] |
() | 脚本表达式 |
String jsonStr = "{'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}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
System.out.println("根节点:" + JSONPath.read(jsonStr, "$"));
System.out.println("根节点下的store节点:" + JSONPath.read(jsonStr, "$.store"));
System.out.println("store节点下的所有子节点:" + JSONPath.read(jsonStr, "$.store.*"));
System.out.println("第一个book节点:" + JSONPath.read(jsonStr, "$.store..book[0]"));
JSONPath | 语义 |
---|---|
$ | 根对象 |
$[-1] | 最后元素 |
$[:-2] | 第1个至倒数第2个 |
$[1:] | 第2个之后所有元素 |
$[1,2,3] | 集合中1、2、3个元素 |
2.3 函数语法
可以在JsonPath表达式执行后进行调用,其输入值为表达式的结果。
函数 | 描述 | 输出类型 |
---|---|---|
min() | 数字数组的最小值 | Double |
max() | 数字数组的最大值 | Double |
avg() | 数字数组的平均值 | Double |
stddev() | 数字数组的标准方差 | Double |
length() | 返回数组的长度 | Integer |
sum() | 数字数组求和 | Double |
keys() | 没搞明白这个函数是做什么的 | Set |
concat(X) | 将数组中元素拼接成一个新的元素 | |
append(X) | 添加新元素到输出数组中 |
String jsonStr = "{'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}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
System.out.println("第一个book节点的价格,并向下取整:" + JSONPath.read(jsonStr, "$.store.book[0].price.floor()"));
2.4 筛选语法
筛选语法用于筛选满足特定条件的节点,是用于过滤数组的逻辑表达式,一个通常的表达式形如:[?(@.age > 18)],可以通过逻辑表达式&&或||组合多个过滤器表达式,例如[?(@.price < 10 && @.category == ‘fiction’)],字符串必须用单引号包围,例如[?(@.color == ‘blue’)]。
操作符 | 描述 |
---|---|
== | 字符串类型对象属性比较过滤。例如$.departs[name = ‘123’],比较操作符支持=、!=、>、>=、<、<= |
> | 数值类型对象属性比较过滤,例如$.departs[id >= 123],比较操作符支持=、!=、>、>=、<、<= |
=~ | 判断是否符合正则表达式 |
like | 字符串类型 like 过滤,例如$.departs[name like ‘sz*’],通配符只支持%,也支持 not like |
rlike | 字符串类型正则匹配过滤,例如departs[name like ‘aa(.)*’],正则语法为jdk的正则语法,支持not rlike |
in | IN 过滤,支持字符串、数值类型。例如: $.departs[name in (‘wenshao’,‘Yako’)] $.departs[id not in (101,102)] |
nin | 排除 |
between | BETWEEN过滤, 支持数值类型,支持not between。例如: $.departs[id between 101 and 201] $.departs[id not between 101 and 201] |
empty | 左边数组或字符串为空 |
size | 左边数组或字符串大小和右边匹配 |
String jsonStr = "{'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}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
System.out.println("选取store节点下,价格小于10的book节点:" + JSONPath.read(jsonStr, "$.store.book[?(@.price < 10)]"));
System.out.println("选取store节点下,价格小于10的book节点:" + JSONPath.eval(jsonStr, "$.store.book[?(@.price < 10)]"));
三、高级用法
JsonPath支持许多高级用法,如动态筛选、多条件筛选、嵌套查询等。
3.1 动态筛选
JsonPath支持使用Java代码动态生成筛选条件。
String jsonStr = "{'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}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
//定义筛选条件
String filter = "$.store.book[?(@.price < %s)].price";
//动态生成筛选条件,获取价格小于10的book节点的价格
Object result = JSONPath.read(jsonStr, String.format(filter, 10));
System.out.println(result.toString());
3.2 多条件筛选
JsonPath支持同时使用多个条件进行筛选。
String jsonStr = "{'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}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
//定义筛选条件
String filter = "$.store.book[?(@.price < %s && @.author == '%s')].title";
//动态生成筛选条件,获取价格小于10且作者是Nigel Rees的book节点的书名
Object result = JSONPath.read(jsonStr, String.format(filter, 10, "Nigel Rees"));
System.out.println(result.toString());
3.3 嵌套查询
JsonPath支持在筛选条件中使用嵌套查询。
四、API
4.1 示例
{
"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 | 获取json中store下book下的所有author值 |
$…author | 获取所有的 author 的值 |
$.store.book.* | 获取json中store下book下的所有值 |
$.store…price | 获取json中store下所有price的值 |
$…book[2] | 获取json中book数组的第3个值 |
$…book[-2] | 倒数的第二本书 |
$…book[0,1] | 前两本书 |
$…book[:2] | 从索引0(包括)到索引2(排除)的所有图书 |
$…book[1:2] | 从索引1(包括)到索引2(排除)的所有图书 |
$…book[-2:] | 获取json中book数组的最后两个值 |
$…book[2:] | 获取json中book数组的第3个到最后一个的区间值 |
$…book[?(@.title)] | 获取json中book数组中包含title的所有节点 |
$.store.book[?(@.price < 10)] | 获取json中book数组中price<10的所有值 |
$…book[?(@.price <= $[‘expensive’])] | 获取json中book数组中price<=$[‘expensive’]结果的所有值 |
*$…book[?(@.author =~ /.REES/i)] | 获取json中book数组中的作者以REES结尾的所有值(REES不区分大小写) |
$…* | 逐层列出json中的所有值,层级由外到内 |
$…book.length() | 获取json中book数组的长度 |
2.2 常用方法
使用Fastjson中的JSONPath解析器,可以调用 JSONPath.read 方法,获取指定的字符串。
List<String> authors = JsonPath.read(JSON_DATA, "$.store.book[*].author");
如果需要多次读,那么这种方法不够理想,因为每次都会重新解析一次json数据
可以看到,在这段难以阅读的json字符串中,我们轻松取到了 author 的值。这只是read方法的用法,下面介绍一下这个类其他的几个关键方法的作用:
public class JSONPath {
// 求值,静态方法
public static Object eval(Object rootObject, String path);
// 计算Size,Map非空元素个数,对象非空元素个数,Collection的Size,数组的长度。其他无法求值返回-1
public static int size(Object rootObject, String path);
// 是否包含path中是否存在对象
public static boolean contains(Object rootObject, String path);
// 是否包含path中是否存在指定值,如果是集合或者数组,在集合中查找value是否存在
public static boolean containsValue(Object rootObject, String path, Object value);
// 修改制定路径的值,如果修改成功,返回true,否则返回false
public static boolean set(Object rootObject, String path, Object value);
// 在数组或者集合中添加元素。添加成功返回 true,失败返回 false
public static boolean arrayAdd(Object rootObject, String path, Object… values);
// 删除指定path的元素, 删除成功返回 true,失败返回 false
public static boolean remove(Object root, String path);
// 编译一个jsonpath为对象
public static JSONPath compile(String path);
// 从一个json字符串中, 根据指定的path读取为Json对象
public static Object read(String json, String path);
// 返回指定Java对象的属性的所有json访问path
public static Map<String, Object> paths(Object javaObject);
}
2.3 类型转换
在java中使用JsonPath时,当我们知道我们读取过后的返回值是什么类型时,JsonPath会尝试将其转换为我们想要的类型,如下所示:
String author = (String) JSONPath.read(JSON_DATA, "$.store.book[0].author");
System.out.println(author);
四、小结
使用JSONPath类提供的静态方法能够非常快速地对json字符串进行路径解析,将指定位置的json字符串以对象的形式返回,方便了系统的调用者。JSONPath与XPath的路径解析规则差不多,熟练使用这种解析方式,再用上Fastjson提供的静态方法,可以将在需要使用JSONPath的项目中将解析速度大大提升。