继 Gson、Jackson、FastJson 之后基于JsonPath解析JSON
基于JsonPath解析JSON
-
- 一、JsonPath 说明
- 二、JsonPath 语法
-
- 1. 常用操作符
- 2. 常用过滤器操作符
- 3. 常用函数
- 三、Java 语言实现JsonPath示例
-
- 1. 引入 maven 坐标
- 2. 数据准备
- 3. json解析示例
- 四、JsonPath 其他功能
一、JsonPath 说明
JsonPath是一种用于读取JSON文档的JavaDSL,能够方便快捷的解析复杂逻辑的Json。GitHub:JsonPath ,当然也可以 在线使用。
二、JsonPath 语法
1. 常用操作符
Operator | Description |
---|---|
$ |
要查询的根元素。表示所有表达式的开始路径 |
@ |
用在筛选器,表示当前节点 |
* |
作为通配符,匹配所有成员 |
.. |
子递归通配符,匹配成员的所有子元素 |
. |
.孩子节点名称 |
['' (, '')] |
括号中标注的一个或多个孩子节点 |
[ (, )] |
括号中标注一个或多个孩子节点的下标(索引),从0开始 |
[start:end] |
表示从start下标开始到 end下标结束(不包括 end 下标)孩子节点 |
[?()] |
过滤表达式。表达式的计算结果必须为布尔值 |
2. 常用过滤器操作符
Operator | Description |
---|---|
== | 左侧等于右侧。但是 1 不等于 ‘1’ |
!= | 左侧不等于右侧 |
< | 左侧小于右侧 |
<= | 左侧小于等于右侧 |
> | 左侧大于右侧 |
>= | 左侧大于等于右侧 |
=~ | 左侧正则匹配右侧 |
in | 左侧存在于右侧集合 |
nin | 左侧不存在于右侧集合 |
size | 左侧(数组或字符串)的大小应与右侧匹配 |
empty | 左侧(数组或字符串)应为空 |
subsetof | 左侧是右侧的子集。测试时发现无法调通 |
anyof | 左侧与右侧的交集。测试时发现无法调通 |
noneof | 左侧和右侧不相交的部分。测试时发现无法调通 |
3. 常用函数
Function | Description | Output type |
---|---|---|
min() | 返回数组的最小值 | Double |
max() | 返回数组的最大值 | Double |
avg() | 返回数组的平均值 | Double |
stddev() | 返回数组的标准方差 | Double |
length() | 返回数组的长度 | Integer |
sum() | 返回数组的总和 | Double |
keys() | 没搞明白这个函数是做什么的 | Set |
concat(X) | 将数组中元素拼接成一个新的元素 | like input |
append(X) | 在 json 上添加元素。测试发现没有作用,提示没有该函数 | like input |
三、Java 语言实现JsonPath示例
1. 引入 maven 坐标
com.jayway.jsonpath json-path 2.7.0
2. 数据准备
添加json文件 /json/ExampleJson.json
,内容如下所示:
{ "store": [ { "name": "京东", "label": "like", "book": [ { "category": "Java", "author": "凯·S·霍斯特曼", "title": "Java核心技术", "price": 149, "nation": "M" }, { "category": "Java", "author": "Bruce Eckel", "title": "Java编程思想", "price": 54.13, "nation": "M" }, { "category": "Java", "author": "方腾飞", "title": "Java并发编程的艺术", "price": 48.12, "nation": "C" }, { "category": "C++", "author": "安东尼威廉姆斯", "title": "C++并发编程实战", "price": 137.00, "nation": "M" }, { "category": "", "author": "未知", "title": "测试", "price": 0, "nation": "C" } ], "bicycle": { "color": "red", "price": 1999.99 }, "avg": 60 }, { "name": "天猫", "book": [ { "category": "Python", "author": "埃里克·马瑟斯 ", "title": "Python从入门到实践", "price": 107, "nation": "M" }, { "category": "Python", "author": "明日科技", "title": "Python从入门到精通", "price": 36.80, "nation": "C" } ] } ], "from": "互联网"}
3. json解析示例
package com.study;import com.jayway.jsonpath.JsonPath;import org.junit.jupiter.api.Assertions;import org.junit.jupiter.api.BeforeEach;import org.junit.jupiter.api.Test;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.IOException;import java.io.InputStream;/ * @author ouyangrongtao * @since 2022-04-20 22:28 */class JsonPathExampleTest { private InputStream resource; private static final Logger LOGGER = LoggerFactory.getLogger(JsonPathExampleTest.class); @BeforeEach void setUp() { resource = JsonPathExample.class.getResourceAsStream("/json/ExampleJson.json"); } @Test void getAllBookListList() throws IOException { Object books = JsonPath.read(resource, "$..book"); LOGGER.info("获取全部 book 节点:{}", books); Assertions.assertNotNull(books); } @Test void getAllBookList() throws IOException { Object books = JsonPath.read(resource, "$..book[*]"); LOGGER.info("获取全部 book 节点:{}", books); Assertions.assertNotNull(books); } @Test void getAllAuthors() throws IOException { Object authors = JsonPath.read(resource, "$..author"); LOGGER.info("获取全部 book 的 author:{}", authors); Assertions.assertNotNull(authors); } @Test void getJingdong() throws IOException { Object o = JsonPath.read(resource, "$.store[0]"); LOGGER.info("获取京东store:{}", o); Assertions.assertNotNull(o); } @Test void getBicycleFromJingdong() throws IOException { Object o = JsonPath.read(resource, "$.store[0].bicycle"); LOGGER.info("获取京东 store 下的 bicycle:{}", o); Assertions.assertNotNull(o); } @Test void getFirstBookFromJingdong() throws IOException { Object o = JsonPath.read(resource, "$.store[0].book[0]"); LOGGER.info("获取京东 store 下的第一的 book:{}", o); Assertions.assertNotNull(o); } @Test void getLastBookFromJingdong() throws IOException { Object o = JsonPath.read(resource, "$.store[0].book[-1]"); LOGGER.info("获取京东 store 下的最后的 book:{}", o); Assertions.assertNotNull(o); } @Test void getFirstBookOfAuthorFromJingdong() throws IOException { Object o = JsonPath.read(resource, "$.store[0].book[0]['author', 'title']"); LOGGER.info("获取京东 store 下的第一的 book 的 author 和 title:{}", o); Assertions.assertNotNull(o); } @Test void getFirstAndThirdBookOfAuthorFromJingdong() throws IOException { Object o = JsonPath.read(resource, "$.store[0].book[0, 2]"); LOGGER.info("获取京东 store 下的第一和第三的 book:{}", o); Assertions.assertNotNull(o); } @Test void getFirstToThirdBookOfAuthorFromJingdong() throws IOException { Object o = JsonPath.read(resource, "$.store[0].book[0:3]"); LOGGER.info("获取京东 store 下的第一到第三的 book:{}", o); Assertions.assertNotNull(o); } @Test void getExistLabel() throws IOException { Object o = JsonPath.read(resource, "$.store[?(@.label)]"); LOGGER.info("获取 store 下存在 label 的 store:{}", o); Assertions.assertNotNull(o); } @Test void getNameEqual() throws IOException { Object o = JsonPath.read(resource, "$.store[?(@.name=='京东')]"); LOGGER.info("获取 name=京东 的 store:{}", o); Assertions.assertNotNull(o); } @Test void getPriceGT100() throws IOException { Object o = JsonPath.read(resource, "$..book[?(@.price > 100)]"); LOGGER.info("获取 price 大于 100 的 book:{}", o); Assertions.assertNotNull(o); } @Test void getPriceGTAvg() throws IOException { Object o = JsonPath.read(resource, "$..book[?(@.price > $.store[0].avg)]"); LOGGER.info("获取 price 大于 avg 的 book:{}", o); Assertions.assertNotNull(o); } @Test void getCategoryEmpty() throws IOException { Object o = JsonPath.read(resource, "$..book[?(@.category == '')]"); LOGGER.info("获取 Java 和 Python 的 book:{}", o); Assertions.assertNotNull(o); } @Test void getJavaAndPython() throws IOException { Object o = JsonPath.read(resource, "$..book[?(@.category in ['Java', 'Python'])]"); LOGGER.info("获取 Java 和 Python 的 book:{}", o); Assertions.assertNotNull(o); } @Test void getMaxPrice() throws IOException { Object o = JsonPath.read(resource, "max($..book[?(@.price)].price)"); LOGGER.info("获取 book 中最高的 price:{}", o); Assertions.assertNotNull(o); } @Test void getConcatPrice1() throws IOException { Object o = JsonPath.read(resource, "concat($..book[?(@.price)].price)"); LOGGER.info("获取 book 中的price并拼接起来:{}", o); Assertions.assertEquals(o, "14954.1348.12137.0010736.8"); } @Test void getConcatPrice2() throws IOException { Object o = JsonPath.read(resource, "$..book[?(@.price)].price.concat()"); LOGGER.info("获取 book 中的price并拼接起来:{}", o); Assertions.assertEquals(o, "14954.1348.12137.0010736.8"); }}
四、JsonPath 其他功能
-
设置指定路径的json值
@Testvoid setValue() { String newJson = JsonPath.parse(resource).set("$.from", "oy").jsonString(); LOGGER.info("设置后的新json:{}", newJson); Assertions.assertNotNull(newJson);}
注意: 设置值的 path 必须存在,否则报
PathNotFoundException
异常。 -
支持缓存,支持自定义
com.jayway.jsonpath.spi.cache.LRUCache
(default, thread safe)
com.jayway.jsonpath.spi.cache.NOOPCache
(no cache)
自定义缓存使用CacheProvider.setCache()
-
JsonProvider SPI
JsonSmartJsonProvider
(default)
JacksonJsonProvider
JacksonJsonNodeJsonProvider
GsonJsonProvider
JsonOrgJsonProvider
JakartaJsonProvider