继 Gson、Jackson、FastJson 之后基于JsonPath解析JSON

一、JsonPath 说明

JsonPath是一种用于读取JSON文档的JavaDSL,能够方便快捷的解析复杂逻辑的Json。GitHub:JsonPath ,当然也可以 在线使用

二、JsonPath 语法

1. 常用操作符

OperatorDescription
$要查询的根元素。表示所有表达式的开始路径
@用在筛选器,表示当前节点
*作为通配符,匹配所有成员
..子递归通配符,匹配成员的所有子元素
.<name>.孩子节点名称
['<name>' (, '<name>')]括号中标注的一个或多个孩子节点
[<number> (, <number>)]括号中标注一个或多个孩子节点的下标(索引),从0开始
[start:end]表示从start下标开始到 end下标结束(不包括 end 下标)孩子节点
[?(<expression>)]过滤表达式。表达式的计算结果必须为布尔值

2. 常用过滤器操作符

OperatorDescription
==左侧等于右侧。但是 1 不等于 ‘1’
!=左侧不等于右侧
<左侧小于右侧
<=左侧小于等于右侧
>左侧大于右侧
>=左侧大于等于右侧
=~左侧正则匹配右侧
in左侧存在于右侧集合
nin左侧不存在于右侧集合
size左侧(数组或字符串)的大小应与右侧匹配
empty左侧(数组或字符串)应为空
subsetof左侧是右侧的子集。测试时发现无法调通
anyof左侧与右侧的交集。测试时发现无法调通
noneof左侧和右侧不相交的部分。测试时发现无法调通

3. 常用函数

FunctionDescriptionOutput type
min()返回数组的最小值Double
max()返回数组的最大值Double
avg()返回数组的平均值Double
stddev()返回数组的标准方差Double
length()返回数组的长度Integer
sum()返回数组的总和Double
keys()没搞明白这个函数是做什么的Set<E>
concat(X)将数组中元素拼接成一个新的元素like input
append(X)在 json 上添加元素。测试发现没有作用,提示没有该函数like input

三、Java 语言实现JsonPath示例

1. 引入 maven 坐标

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.7.0</version>
</dependency>

2. 数据准备

添加json文件 /json/ExampleJson.json ,内容如下所示:

{
  "store": [
    {
      "name": "京东",
      "label": "like",
      "book": [
        {
          "category": "Java",
          "author": "凯·S·霍斯特曼",
          "title": "Java核心技术",
          "price": 149,
          "nation": "M"
        },
        {
          "category": "Java",
          "author": "Bruce Eckel",
          "title": "Java编程思想",
          "price": 54.13,
          "nation": "M"
        },
        {
          "category": "Java",
          "author": "方腾飞",
          "title": "Java并发编程的艺术",
          "price": 48.12,
          "nation": "C"
        },
        {
          "category": "C++",
          "author": "安东尼威廉姆斯",
          "title": "C++并发编程实战",
          "price": 137.00,
          "nation": "M"
        },
        {
          "category": "",
          "author": "未知",
          "title": "测试",
          "price": 0,
          "nation": "C"
        }
      ],
      "bicycle": {
        "color": "red",
        "price": 1999.99
      },
      "avg": 60
    },
    {
      "name": "天猫",
      "book": [
        {
          "category": "Python",
          "author": "埃里克·马瑟斯 ",
          "title": "Python从入门到实践",
          "price": 107,
          "nation": "M"
        },
        {
          "category": "Python",
          "author": "明日科技",
          "title": "Python从入门到精通",
          "price": 36.80,
          "nation": "C"
        }
      ]
    }
  ],
  "from": "互联网"
}

3. json解析示例

package com.study;


import com.jayway.jsonpath.JsonPath;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author ouyangrongtao
 * @since 2022-04-20 22:28
 */
class JsonPathExampleTest {

    private InputStream resource;
    private static final Logger LOGGER = LoggerFactory.getLogger(JsonPathExampleTest.class);

    @BeforeEach
    void setUp() {
        resource = JsonPathExample.class.getResourceAsStream("/json/ExampleJson.json");
    }

    @Test
    void getAllBookListList() throws IOException {
        Object books = JsonPath.read(resource, "$..book");
        LOGGER.info("获取全部 book 节点:{}", books);
        Assertions.assertNotNull(books);
    }

    @Test
    void getAllBookList() throws IOException {
        Object books = JsonPath.read(resource, "$..book[*]");
        LOGGER.info("获取全部 book 节点:{}", books);
        Assertions.assertNotNull(books);
    }

    @Test
    void getAllAuthors() throws IOException {
        Object authors = JsonPath.read(resource, "$..author");
        LOGGER.info("获取全部 book 的 author:{}", authors);
        Assertions.assertNotNull(authors);
    }

    @Test
    void getJingdong() throws IOException {
        Object o = JsonPath.read(resource, "$.store[0]");
        LOGGER.info("获取京东store:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getBicycleFromJingdong() throws IOException {
        Object o = JsonPath.read(resource, "$.store[0].bicycle");
        LOGGER.info("获取京东 store 下的 bicycle:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getFirstBookFromJingdong() throws IOException {
        Object o = JsonPath.read(resource, "$.store[0].book[0]");
        LOGGER.info("获取京东 store 下的第一的 book:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getLastBookFromJingdong() throws IOException {
        Object o = JsonPath.read(resource, "$.store[0].book[-1]");
        LOGGER.info("获取京东 store 下的最后的 book:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getFirstBookOfAuthorFromJingdong() throws IOException {
        Object o = JsonPath.read(resource, "$.store[0].book[0]['author', 'title']");
        LOGGER.info("获取京东 store 下的第一的 book 的 author 和 title:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getFirstAndThirdBookOfAuthorFromJingdong() throws IOException {
        Object o = JsonPath.read(resource, "$.store[0].book[0, 2]");
        LOGGER.info("获取京东 store 下的第一和第三的 book:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getFirstToThirdBookOfAuthorFromJingdong() throws IOException {
        Object o = JsonPath.read(resource, "$.store[0].book[0:3]");
        LOGGER.info("获取京东 store 下的第一到第三的 book:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getExistLabel() throws IOException {
        Object o = JsonPath.read(resource, "$.store[?(@.label)]");
        LOGGER.info("获取 store 下存在 label 的 store:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getNameEqual() throws IOException {
        Object o = JsonPath.read(resource, "$.store[?(@.name=='京东')]");
        LOGGER.info("获取 name=京东 的 store:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getPriceGT100() throws IOException {
        Object o = JsonPath.read(resource, "$..book[?(@.price > 100)]");
        LOGGER.info("获取 price 大于 100 的 book:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getPriceGTAvg() throws IOException {
        Object o = JsonPath.read(resource, "$..book[?(@.price > $.store[0].avg)]");
        LOGGER.info("获取 price 大于 avg 的 book:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getCategoryEmpty() throws IOException {
        Object o = JsonPath.read(resource, "$..book[?(@.category == '')]");
        LOGGER.info("获取 Java 和 Python 的 book:{}", o);
        Assertions.assertNotNull(o);
    }

    @Test
    void getJavaAndPython() throws IOException {
        Object o = JsonPath.read(resource, "$..book[?(@.category in ['Java', 'Python'])]");
        LOGGER.info("获取 Java 和 Python 的 book:{}", o);
        Assertions.assertNotNull(o);
    }
    
    @Test
    void getMaxPrice() throws IOException {
        Object o = JsonPath.read(resource, "max($..book[?(@.price)].price)");
        LOGGER.info("获取 book 中最高的 price:{}", o);
        Assertions.assertNotNull(o);
    }
    
    @Test
    void getConcatPrice1() throws IOException {
        Object o = JsonPath.read(resource, "concat($..book[?(@.price)].price)");
        LOGGER.info("获取 book 中的price并拼接起来:{}", o);
        Assertions.assertEquals(o, "14954.1348.12137.0010736.8");
    }

    @Test
    void getConcatPrice2() throws IOException {
        Object o = JsonPath.read(resource, "$..book[?(@.price)].price.concat()");
        LOGGER.info("获取 book 中的price并拼接起来:{}", o);
        Assertions.assertEquals(o, "14954.1348.12137.0010736.8");
    }
}

四、JsonPath 其他功能

  1. 设置指定路径的json值

    @Test
    void setValue() {
        String newJson = JsonPath.parse(resource).set("$.from", "oy").jsonString();
        LOGGER.info("设置后的新json:{}", newJson);
        Assertions.assertNotNull(newJson);
    }
    

    注意: 设置值的 path 必须存在,否则报 PathNotFoundException 异常。

  2. 支持缓存,支持自定义
    com.jayway.jsonpath.spi.cache.LRUCache (default, thread safe)
    com.jayway.jsonpath.spi.cache.NOOPCache (no cache)
    自定义缓存使用 CacheProvider.setCache()

  3. JsonProvider SPI
    JsonSmartJsonProvider (default)
    JacksonJsonProvider
    JacksonJsonNodeJsonProvider
    GsonJsonProvider
    JsonOrgJsonProvider
    JakartaJsonProvider

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lytao123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值