基於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的最簡單,最直接的方法是通過靜態readAPI。

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

5. 參考

JsonPath教程

JSONPath-簡單入門

JsonPath的用法

jsonpath github


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM