JsonPath 基本使用

一、JSONPath 介绍

XML 格式的优点之一是可以使用很多工具来分析、转换和有选择地从 XML 文档中提取数据。 XPath 就是这些强大的工具之一。而对于 JSON 文档,也有类似的 JSONPath 规范(可以说是事实上的业内标准)。

通俗易懂地讲,就是可以通过形如 $.tool.jsonpath.creator 的「路径」来表示 JSON 文档内部嵌套的任意属性与值。

Jayway JsonPath 就是 JSONPath 规范的一个广为使用的 Java 实现。本文就简要介绍该库的基本使用。

此外,alibaba 的 fastjson 也支持 JSONPath。

二、使用示例

以如下的 JSON 文本举例:

{
    "tool": {
        "jsonpath": {
            "creator": {
                "name": "Jayway Inc.",
                "location": [
                    "Malmo",
                    "San Francisco",
                    "Helsingborg"
                ]
            }
        }
    },
    "book": [
        {
            "title": "Beginning JSON",
            "price": 49.99
        },
        {
            "title": "JSON at Work",
            "price": 29.99
        }
    ]
}

2.1 基本语法:

  • $ 表示根节点,@ 表示当前节点,* 表示通配符;
  • 使用 . 或者 [] 分隔节点及其相邻节点。例如,用 $.tool.jsonpath.creator.location[2] 或者 $['tool']['jsonpath']['creator']['location'][2] 都可以获取到上面 JSON 文本里的"Helsingborg"

2.2 主要 API:

  • <T> T JsonPath.read(String jsonString, String jsonPath, Predicate... filters);
  • <T> T JsonPath.parse(String jsonString).read(String jsonPath, Predicate... filters);

话不多说,直接上代码:

import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.spi.json.GsonJsonProvider;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.mapper.GsonMappingProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;

public class JsonPathTest {

    /**
     * <pre> json:
     * {
     *     "tool": {
     *         "jsonpath": {
     *             "creator": {
     *                 "name": "Jayway Inc.",
     *                 "location": [
     *                     "Malmo",
     *                     "San Francisco",
     *                     "Helsingborg"
     *                 ]
     *             }
     *         }
     *     },
     *     "book": [
     *         {
     *             "title": "Beginning JSON",
     *             "price": 49.99
     *         },
     *         {
     *             "title": "JSON at Work",
     *             "price": 29.99
     *         }
     *     ]
     * }
     * </pre>
     */
    private static final String json = "{\"tool\":{\"jsonpath\":{\"creator\":{\"name\":\"Jayway Inc.\",\"location\":[\"Malmo\",\"San Francisco\",\"Helsingborg\"]}}},\"book\":[{\"title\":\"Beginning JSON\",\"price\":49.99},{\"title\":\"JSON at Work\",\"price\":29.99}]}";

    public static void main(String[] args) throws Exception {
        String path1 = "$.tool.jsonpath.creator.location[1]";
        String path2 = "$['tool']['jsonpath']['creator']['location'][*]";
        String path3 = "$.book..title";
        String path4 = "$.book[1]";

        DocumentContext jsonContext = JsonPath.parse(json);
        // 读出来的对象是 1.Java原生类型 或者 2.JsonPath 库的类型
        Object o1 = JsonPath.read(json, path1);   // class java.lang.String
        Object o2 = jsonContext.read(path2);   // class net.minidev.json.JSONArray
        // 可以直接用正确的类型接收返回值
        net.minidev.json.JSONArray o3 = jsonContext.read(path3);
        java.util.LinkedHashMap o4 = jsonContext.read(path4);   // 很奇怪 o4 的类型是 Map 而不是 net.minidev.json.JSONObject


        // 如果想使用 Gson 的 JSON 动态类型,需要
        Configuration gsonConf = Configuration.builder()
                .jsonProvider(new GsonJsonProvider())
                .mappingProvider(new GsonMappingProvider())
                .build();
        DocumentContext gsonContext = JsonPath.using(gsonConf).parse(json);
        Object g1 = gsonContext.read(path1);   // class com.google.gson.JsonPrimitive
        Object g2 = gsonContext.read(path2);   // class com.google.gson.JsonObject
        com.google.gson.JsonArray g3 = gsonContext.read(path3);
        com.google.gson.JsonObject g4 = gsonContext.read(path4);


        // 如果想使用 Jackson 的 JSON 动态类型,需要
        Configuration jacksonConf = Configuration.builder()
                .jsonProvider(new JacksonJsonNodeJsonProvider()) // 注意:不是 JacksonJsonProvider
                .mappingProvider(new JacksonMappingProvider())
                .build();
        DocumentContext jacksonContext = JsonPath.using(jacksonConf).parse(json);
        Object k1 = jacksonContext.read(path1);   // class com.fasterxml.jackson.databind.node.TextNode
        Object k2 = jacksonContext.read(path2);   // class com.fasterxml.jackson.databind.node.ObjectNode
        com.fasterxml.jackson.databind.node.ArrayNode k3 = jacksonContext.read(path3);
        com.fasterxml.jackson.databind.node.ObjectNodek4 = jacksonContext.read(path4);
    }
}

注意几个地方:

  • read()方法返回值使用了泛型,所以可以用任意类型来接收返回值。但是如果使用了错误的类型,则会抛出java.lang.ClassCastException
  • 如果想使用Gson或者Jackson的 JSON 动态类型,需要配置Configuration后再解析。至于这两个 JSON 库的基本介绍与使用在我的前一篇博文中有讲。

最后,更多语法以及高级用法(如PredicatesOptions等)可以自行去查阅 JSONPath 规范Jayway JsonPath 的文档。

参考:
https://www.baeldung.com/guide-to-jayway-jsonpath

posted @ 2022-05-15 20:52  Recycer  阅读(779)  评论(0编辑  收藏  举报