fastjson的JSONPath是一种查询和导航JSON文档的路径表达式语言,用于从JSON数据结构中提取和筛选数据。对于复杂的json数据结构,在进行获取和判断操作时,不需层层的去get,可以通过简洁的JsonPath表达式精准找到需要的部分。
官方地址:https://github.com/alibaba/fastjson/wiki/JSONPath
依赖项
xml
<!-- JSONObject -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
样例数据
java
String jsonStr =
"{'store':" +
"{'book':[" +
"{'category':'reference','author':'Nigel Rees','title':'Sayings of the Century','price':8.95}," +
"{'category':'reference','author':'陈渠珍(ChenQuzhen)','title':'艽野尘梦','price':10.95}," +
"{'category':'reference','author':'','title':'刀戟戡魔录','price':10.95}," +
"{'category':'fiction','author':'Evelyn Waugh','title':'Sword of Honour','price':12.99}]," +
"'bicycle':{'color':'red','price':19.95}" +
"}" +
"}";
JSONObject jsonObject = JSON.parseObject(jsonStr);
根据需要解析的路径,使用JsonPath类的静态方法read() 解析json字符串。如果是json格式的字符串,则先解析为JSONObject,然后就能直接使用JSONPath.eval()方法了,样例如下:
一、基本语法
| JSONPath | 描述 |
|---|---|
| $ | 文档的根对象 |
| @ | 文档当前节点对象,类似于java 中的 this 字段 |
| . | 当前节点的子节点,如 $.name |
| [num] | 数组访问,num是数字,可以是负数。如 $[0].leader.departments[-1].name |
| [num0,num1,num2] | 数组多个元素访问,num 是数字,可以是负数,返回数组中的多个元素。如 $[0,1,-2,5] |
| [start:end] | 数组范围访问,start、end 是开始、结束的下标,可以是负数,返回数组中的多个元素。 |
| ['key'] | 属性访问。如 $['name'] |
| ['key0','key1'] | 多个属性访问。如 $['id','name'] |
| .. | 可以理解为递归搜索,递归匹配所有子元素。如 $..name |
| * | 通配符,取所有value集合,如$.leader.* |
利用上述基本语法可以提取JSON结构中的特定数据,样例如下:
java
/*
* JSONPath.eval(jsonStr, "$.") 提取对应节点的数据
* JSONPath.remove(jsonStr, "$.") 删除对应的节点数据
* JSONPath.set(jsonStr, "$.userInfo.addData", "sinder") 插入指定的值,甚至可以直接操作json中的数组或者对象数据。
*/
JSONObject jsonRoot = (JSONObject) JSONPath.read(jsonStr, "$");
JSONObject jsonStore = (JSONObject) JSONPath.read(jsonStr, "$.store");
Collection<JSONObject> jsonStoreVals = (Collection<JSONObject>) JSONPath.read(jsonStr, "$.store.*");
JSONObject jsonBook0 = (JSONObject) JSONPath.read(jsonStr, "$.store..book[0]");
List<String> authors = (List<String>)JSONPath.read(jsonStr, "$..author");
System.out.println("根节点:" + jsonRoot);
System.out.println("根节点下的store节点:" + jsonStore);
System.out.println("store节点的所有value集合:" + jsonStoreVals);
System.out.println("store节点下的首个book节点:" + jsonBook0); // {"author":"Nigel Rees","price":8.95,"category":"reference","title":"Sayings of the Century"}
System.out.println("根节点下的所有author的value集合:" + authors); // [Nigel Rees, 陈渠珍(ChenQuzheng), Evelyn Waugh]
Collection<Object> bicycleVals = (Collection<Object>) JSONPath.eval(jsonObject, "$.store.bicycle.*");
Collection<Object> bicycleVals2 = (Collection<Object>)JSONPath.eval(jsonObject, "$.store.bicycle['color','price']");
List<String> bookAuthors = (List<String>) JSONPath.read(jsonStr, "$.store.book[*].author");
System.out.println("bicycle节点的所有value集合:" + bicycleVals);
System.out.println("bicycle节点的color和price的value集合:" + bicycleVals2);
System.out.println("book节点的author属性值:" + bookAuthors); // ["Nigel Rees","陈渠珍(ChenQuzheng)","Evelyn Waugh"]
Integer size = (Integer)JSONPath.eval(jsonObject, "$.store.book.size()");
String title = (String)JSONPath.eval(jsonObject, "$.store.book[0].title");
System.out.println("book数量:" + size);
System.out.println("第一本书title:" + title);
二、函数语法
java
System.out.println("首个book节点的价格,并向下取整:" + JSONPath.read(jsonStr, "$.store.book[0].price.floor()"));
System.out.println("book节点price的个数:" + JSONPath.read(jsonStr, "$.store.book['price'].length()"));
System.out.println("book节点price的最小值:" + JSONPath.read(jsonStr, "$.store.book['price'].min()"));
System.out.println("book节点price的最大值:" + JSONPath.read(jsonStr, "$.store.book['price'].max()"));
// System.out.println("book节点price的平均值:" + JSONPath.read(jsonStr, "$.store.book['price'].avg()"));
// System.out.println("book节点price的标准差:" + JSONPath.read(jsonStr, "$.store.book['price'].stddev()"));
// System.out.println("book节点price的平均值:" + JSONPath.read(jsonStr, "$.store.book['price'].sum()"));
三、筛选语法
| JSONPath | 描述 |
|---|---|
| [?(expression)] | 过滤器表达式,必须返回一个布尔值,如 $.departs[?(@.name != null && @.name != '')] |
筛选语法是用于过滤数组的逻辑表达式,如:[?(@.price > 10)]。可以使用 &&、|| 组合多个过滤器表达式,如:[?(@.price < 10 && @.category == 'reference')],其中,字符串常量必须用单引号包围。筛选语法支持的符号如下:
1、== != > >= < <= 数值和字符串的比较
java
JSONArray ja1 = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.price < 10 && @.category == 'reference')]");
JSONArray ja2 = (JSONArray) JSONPath.eval(jsonStr, "$.store.book[?(@.price < 10 && @.category == 'reference')]");
System.out.println("筛选store节点下price小于10的book节点:" + ja1);
System.out.println("筛选store节点下price小于10的book节点:" + ja2);
String firstBookTitle = (String)JSONPath.eval(jsonObject, "$.store.book[price > 10][0].title");
System.out.println("筛选store节点下price大于10元的title(第一本):" + firstBookTitle);
2、between查询数值范围内,not between查询数值范围外 TODO 不支持 !!!
java
/// JSONArray between = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.price between 10 and 12)]");
/// System.out.println("between查询数值范围内:" + between);
3、in查询数值范围内,nin查询数值范围外 TODO 只对字符串友好 !!!
java
JSONArray in = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.category in ('fiction'))]");
JSONArray nin = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.category nin ('fiction'))]");
System.out.println("in查询字符串范围内:" + in);
System.out.println("nin查询字符串范围外:" + nin);
4、字符串非空
java
JSONArray ja7 = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.author != null && @.author != '')]");
System.out.println("有作者的书:" + ja7);
5、like 'xxx%'字符串模糊查询, not like '%'字符串模糊查询,
java
JSONArray ja3 = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.author like '陈%')]");
JSONArray ja4 = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.author not like '陈%')]");
System.out.println("陈氏作者写的书:" + ja3);
System.out.println("其他作者写的书:" + ja4);
6、rlike 'xxx'字符串正则匹配,not rlike 'xxx'字符串正则排除
java
JSONArray ja5 = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.author rlike '[\\w\\s]+')]");
JSONArray ja6 = (JSONArray) JSONPath.read(jsonStr, "$.store.book[?(@.author not rlike '[\\w\\s]+')]");
System.out.println("英文作者写的书(正则匹配):" + ja5);
System.out.println("其他作者写的书(正则排除):" + ja6);