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());
}
}