基于java对jsonpath的初步学习
1. 介绍
类似于XPath在xml文档中的定位,JsonPath表达式通常是用来路径检索或设置Json的。
2. 语法(操作符)
操作员 | 描述 |
---|---|
` | 操作员 |
------------------------- | ------------------------------------------------------------ |
| 要查询的根元素。用于表示一个json数据,可以是数组或对象 |
| @
| 过滤器断言(filter predicate)处理的当前节点对象,类似于java中的this字段 |
| *
| 通配符,可以表示一个名字或数字 |
| ..
| 可以理解为递归搜索,深层扫描。可在任何需要名称的地方使用。 |
| .<name>
| 表示一个子节点 |
| ['<name>' (, '<name>')]
| 表示一个或多个子节点 |
| [<number> (, <number>)]
| 表示一个或多个数组下标 |
| [start:end]
| 数组片段,区间为[start,end),不包含end |
| [?(<expression>)]
| 过滤表达式。表达式必须计算为布尔值。 |
2. 语法(函数)
可以在JsonPath表达式执行后进行调用,其输入值为表达式的结果。
功能 | 描述 | 输出量 |
---|---|---|
min() | 提供数值类型数组的最小值 | Double |
max() | 提供数值类型数组的最大值 | Double |
avg() | 提供数值类型数组的平均值 | Double |
stddev() | 提供数值类型数组的标准偏差值 | Double |
length() | 提供数值类型数组的长度 | Integer |
sum() | 提供数值类型数组的总和 | Double |
2. 语法(过滤器)
过滤器是用于过滤数组的逻辑表达式,一个通常的表达式形如:[?(@.age > 18)]
,可以通过逻辑表达式&&或||组合多个过滤器表达式,例如[?(@.price < 10 && @.category == ‘fiction’)]
,字符串必须用单引号或双引号包围,例如[?(@.color == ‘blue’)] or [?(@.color == “blue”)]
。
操作符 | 描述 |
---|---|
== | 等于符号,但数字1不等于字符1(note that 1 is not equal to ‘1’) |
!= | 不等于符号 |
< | 小于符号 |
<= | 小于等于符号 |
> | 大于符号 |
>= | 大于等于符号 |
=~ | 判断是否符合正则表达式,例如[?(@.name =~ /foo.*?/i)] |
in | 所属符号,例如[?(@.size in [‘S’, ‘M’])] |
nin | 排除符号 |
subsetof | 左边是右边的一个子集[?(@.sizes subsetof ['S', 'M', 'L'])] |
anyof | 左与右有交集 [?(@.sizes anyof ['M', 'L'])] |
noneof | 左与右没有交集 [?(@.sizes noneof ['M', 'L'])] |
size | 左边(数组或字符串)的大小应与右边匹配 |
empty | 判空符号 |
3. 官方示例参考
{
"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 |
所有书籍的作者 |
$..author |
所有作者 |
$.store.* |
所有东西,包括书籍和自行车 |
$.store..price |
所有东西的价格 |
$..book[2] |
第三本书 |
$..book[-2] |
倒数第二本书 |
$..book[0,1] |
前两本书 |
$..book[:2] |
All 从索引0(含)到索引2(不含)的图书 |
$..book[1:2] |
从索引1(含)到索引2(不含)的图书 |
$..book[-2:] |
最后两本书 |
$..book[2:] |
从尾数第二本书 |
$..book[?(@.isbn)] |
所有带有ISBN号的图书 |
$.store.book[?(@.price < 10)] |
商店中所有价格低于10书籍 |
$..book[?(@.price <= $['expensive'])] |
商店中所有非“昂贵”的图书 |
$..book][?(@.author =~ /.*REES/i)] |
所有与正则表达式匹配的书籍(忽略大小写) |
$..* |
所有数据 |
4. javaDemo 测试
新建maven项目最终的pom.xml
文件如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>studyJsonPath</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- jsonpath jar包 -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
</dependencies>
<build>
<finalName>jsonpathDemo</finalName>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
测试用的json文件如上
使用JsonPath的最简单,最直接的方法是通过静态read
API。
import com.jayway.jsonpath.JsonPath;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* @author john
* @date 2020/4/8 - 17:31
*/
public class JsonPathStudyDemo {
public static void main(String[] args) throws IOException {
File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
String json = FileUtils.readFileToString(file);
List<String> authors = JsonPath.read(json, "$.store.book[*].author");
System.out.println(authors);
}
}
如果仅是单次使用是OK的,如果是多次使用的话,为了避免每次解析json都需要调用JsonPath.read(...),你可以先解析json
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
/**
* @author john
* @date 2020/4/8 - 17:31
*/
public class JsonPathStudyDemo {
public static void main(String[] args) throws IOException {
File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
String json = FileUtils.readFileToString(file);
Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
String author0 = JsonPath.read(document, "$.store.book[0].author");
String author1 = JsonPath.read(document, "$.store.book[1].author");
System.out.println(author0);
System.out.println(author1);
}
}
JsonPath还提供了流式的API。这也是最灵活的一种。
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ReadContext;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @author john
* @date 2020/4/8 - 17:31
*/
public class JsonPathStudyDemo {
public static void main(String[] args) throws IOException {
File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
String json = FileUtils.readFileToString(file);
ReadContext ctx = JsonPath.parse(json);
List<String> authorsOfBooksWithISBN = ctx.read("$.store.book[?(@.isbn)].author");
List<Map<String, Object>> expensiveBooks = JsonPath
// .using(configuration)
.parse(json)
.read("$.store.book[?(@.price > 10)]", List.class);
System.out.println(authorsOfBooksWithISBN);
System.out.println(expensiveBooks);
}
}
默认情况下,MappingProvider SPI提供了一个简单的对象映射器。这使您可以指定所需的返回类型,并且MappingProvider将尝试执行映射。在下面的示例中,演示了Long和Date之间的映射。
import com.jayway.jsonpath.JsonPath;
import java.io.IOException;
import java.util.Date;
/**
* @author john
* @date 2020/4/8 - 17:31
*/
public class JsonPathStudyDemo {
public static void main(String[] args) throws IOException {
String json = "{\"date_as_long\" : 1411455611975}";
Date date = JsonPath.parse(json).read("$['date_as_long']", Date.class);
System.out.println(date);
}
}
如果将JsonPath配置为使用JacksonMappingProvider或GsonMappingProvider,您甚至可以将JsonPath输出直接映射到POJO。
先修改pom.xml
,添加如下依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
新建bean文件
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
/**
* @author john
* @date 2020/4/8 - 18:13
*/
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Book {
private String category;
private String author;
private String title;
private String isbn;
private double price;
}
进行测试
import cn.demo.bean.Book;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.EnumSet;
import java.util.Set;
/**
* @author john
* @date 2020/4/8 - 17:31
*/
public class JsonPathStudyDemo {
public static void main(String[] args) throws IOException {
File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
String json = FileUtils.readFileToString(file);
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonNodeJsonProvider();
private final MappingProvider mappingProvider = new JacksonMappingProvider();
@Override
public JsonProvider jsonProvider() {
return jsonProvider;
}
@Override
public MappingProvider mappingProvider() {
return mappingProvider;
}
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
}
});
Book book = JsonPath.parse(json).read("$.store.book[0]", Book.class);
System.out.println(book);
}
}
要获取完整的泛型类型信息,请使用TypeRef。
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.TypeRef;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
/**
* @author john
* @date 2020/4/8 - 17:31
*/
public class JsonPathStudyDemo {
public static void main(String[] args) throws IOException {
File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
String json = FileUtils.readFileToString(file);
Configuration.setDefaults(new Configuration.Defaults() {
private final JsonProvider jsonProvider = new JacksonJsonNodeJsonProvider();
private final MappingProvider mappingProvider = new JacksonMappingProvider();
@Override
public JsonProvider jsonProvider() {
return jsonProvider;
}
@Override
public MappingProvider mappingProvider() {
return mappingProvider;
}
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
}
});
TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {};
List<String> titles = JsonPath.parse(json).read("$.store.book[*].title", typeRef);
System.out.println(titles);
}
}
向json中指定位置添加内容
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
/**
* @author john
* @date 2020/4/8 - 17:31
*/
public class JsonPathStudyDemo {
public static void main(String[] args) throws IOException {
File file = new File(JsonPathStudyDemo.class.getClassLoader().getResource("test.json").getPath());
String json = FileUtils.readFileToString(file);
DocumentContext document = JsonPath.parse(json).put("$.store.book[*]", "kind", "paper");
System.out.println(document.jsonString());
}
}