JSONPath解析JSON数据结构

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);
相关推荐
无限进步_2 小时前
【C语言】用队列实现栈:数据结构转换的巧妙设计
c语言·开发语言·数据结构·c++·链表·visual studio
liu****2 小时前
02_Pandas_数据结构
数据结构·python·pandas·python基础
xiaoliuliu123452 小时前
Tomcat Connectors 1.2.32 源码编译安装教程(含 mod_jk 配置步骤)
java·tomcat
CYTElena2 小时前
JAVA关于集合的笔记
java·开发语言·笔记
源码获取_wx:Fegn08952 小时前
基于springboot + vueOA工程项目管理系统
java·vue.js·spring boot·后端·spring
短剑重铸之日2 小时前
《Java并发编程研读》第三章:锁机制
java·java并发编程·java锁机制
一 乐2 小时前
健康管理|基于springboot + vue健康管理系统(源码+数据库+文档)
java·前端·数据库·vue.js·spring boot·后端·学习
是三好2 小时前
分布式事务seata
java·分布式·seata
optimistic_chen3 小时前
【Redis 系列】常用数据结构---Hash类型
linux·数据结构·redis·分布式·哈希算法