JsonPath:针对json的强大的规则解析与参数查找工具
项目特点
GitHub项目地址:https://github.com/json-path/JsonPath
主要功能:
- 将Json字符串转为Java Map对象(这个不算什么,FastJson之类的工具都可以)
- 通过强大的规则表达式定位字段,返回字段值或值集合(很厉害)
支持的规则表达式以及示例(选自项目readme):
JsonPath (点击测试) | 结果 |
---|---|
$.store.book[*].author | The authors of all books |
$..author | All authors |
$.store.* | All things, both books and bicycles |
$.store..price | The price of everything |
$..book[2] | The third book |
$..book[-2] | The second to last book |
$..book[0,1] | The first two books |
$..book[:2] | All books from index 0 (inclusive) until index 2 (exclusive) |
$..book[1:2] | All books from index 1 (inclusive) until index 2 (exclusive) |
$..book[-2:] | Last two books |
$..book[2:] | Book number two from tail |
$..book[?(@.isbn)] | All books with an ISBN number |
$.store.book[?(@.price < 10)] | All books in store cheaper than 10 |
$..book[?(@.price <= $['expensive'])] | All books in store that are not "expensive" |
$..book[?(@.author =~ /.*REES/i)] | All books matching regex (ignore case) |
$..* | Give me every thing |
$..book.length() | The number of books |
实战测试
就用项目readme文档提供的例子进行测试:
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
}
POM中引入依赖:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.7.0</version>
</dependency>
写一个单元测试类:
@SpringBootTest
@RunWith(MockitoJUnitRunner.class)
public class JsonPathTest {
private final String jsonStr = "...";
private final Object context = Configuration.defaultConfiguration().jsonProvider().parse(jsonStr);
@Test
public void test(){}
}
其中:
- 第二个注解可以做到启动SpringBoot测试类而无需启动SpringApplication,并且也可以做到组件注入等功能。
- jsonStr用来指代之前所述的json字符串,这里简略写。
- context实际上是由json字符串通过默认配置生成的一个Map<String, Object>。
先看看context的类型:
System.out.println("context的类型:" + context.getClass().getSimpleName() + "\n");
------------------------------------------------------------------
output: context的类型:LinkedHashMap
用法1:通过key定位一个value:
jsonpath = "$.store.book[1].price";
result = JsonPath.read(testMap, jsonpath);
System.out.println("contents on " + jsonpath + ": " + result + "\n");
------------------------------------------------------------------
output: contents on $.store.book[1].price: 12.99
用法2:通过key定位一组value:
jsonpath = "$.store.book[*].price";
result = JsonPath.read(context, jsonpath);
System.out.println("contents on " + jsonpath + ": " + result + "\n");
------------------------------------------------------------------
output: contents on $.store.book[*].price: [8.95,12.99,8.99,22.99]
这里如果去查看result的type,会发现它是JSONArray类型,是List<Object>接口的实现,当List用就可以了。
用法3:向下递归查找:
jsonpath = "$..price";
result = JsonPath.read(context, jsonpath);
System.out.println("contents on " + jsonpath + ": " + result);
------------------------------------------------------------------
output: contents on $..price: [8.95,12.99,8.99,22.99,19.95]
在测试的时候想起一个问题,设想这样的场景,如果我们已经有了这样一个Map,只需要JsonPath提供的规则表达式解析与查找能力,那么想要使用JsonPath是不是需要Map->JsonString->context->规则解析->查找结果?答案是不需要的。
我们已经知道这个context本就是一个Map类型,那么是不是可以省去中间转为json string的步骤呢?我们测试看看:
//1. 先将json解析为一个Map
Map<String, Object> testMap = (Map) JSONObject.parseObject(JSON_STRING);
jsonpath = "$..price";
//2. 再将Map传入read方法,看是否能查找到结果:
result = JsonPath.read(testMap, jsonpath);
System.out.println("contents on " + jsonpath + ": " + result);
------------------------------------------------------------------
output: contents on $..price: [8.95,12.99,8.99,22.99,19.95]
可以看出,JsonPath的搜索规则解析能力是支持对普通Map进行查找的。