强大!JSON解析神器,再复杂也不怕了

开发 开发工具
当你面对一个嵌套层级很多、结构复杂的JSON对象时,你是否觉得逐一创建对应的Java实体类(或者是Map)来接收这些数据既繁琐又低效?

环境:SpringBoot3.4.0

1. 简介

你是否遇到过需要从一个复杂的JSON结构中提取特定信息的场景?

当你面对一个嵌套层级很多、结构复杂的JSON对象时,你是否觉得逐一创建对应的Java实体类(或者是Map)来接收这些数据既繁琐又低效?

在进行单元测试或模拟请求时,你是否需要构建或修改JSON数据?

在测试过程中,我们可能需要构建特定的JSON请求体或修改响应数据。有没有一种工具可以帮助我们轻松地完成这些操作?

答案是肯定的!有一种名为JSONPath的工具,它提供了一种类似于XPath的表达式语言,用于在JSON文档中查询和操作数据。JSONPath不仅能够高效地定位和提取JSON中的特定信息,还支持数据过滤、转换和更新等操作。

2. 实战案例

2.1 准备环境

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

如果你是基于Spring Boot环境,那么你不需要指定版本,Spring Boot已经帮我们管理了该组件的版本。截至撰写该篇文章时,JSONPath的最新版本是2.9.0。

说明:JsonPath表达式总是以与XPath表达式在XML文档中结合使用相同的方式来引用JSON结构。在JsonPath中,“根成员对象”无论是对象还是数组,总是被引用为$。

2.2 语法介绍

JsonPath 表达式可以使用点符号"."

$.store.book[0].title

也可以使用括号表示法

$['store']['book'][0]['title']

操作符

操作

说明

$

查询的根元素,所有路径表达式的起点

@

由过滤器谓词处理的当前节点

*

通配符,在需要名称或数字的位置可用

..

深度扫描,在需要名称的位置可用

.<name>

点表示法的子节点

['<name>' (, '<name>')]

方括号表示法的子节点或子节点集合

[<number> (, <number>)]

数组索引或索引集合

[start:end]

数组切片操作符

[?(<expression>)]

过滤器表达式,表达式必须计算为布尔值

函数

函数可以在路径的末尾被调用——函数的输入是路径表达式的输出。函数的输出由函数本身决定。支持如下的函数:

过滤操作

过滤器是用于筛选数组的逻辑表达式。一个典型的过滤器可能是[?(@.age > 18)],其中@代表当前正在处理的项。可以使用逻辑运算符&&和||创建更复杂的过滤器。字符串字面量必须用单引号或双引号括起来(例如[?(@.color == 'blue')]或[?(@.color == "blue")])。支持如下过滤:

操作符

说明

==

左值等于右值(注意1不等于'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

左值(数组或字符串)应为空

接下来,我们介绍具体的使用示例。

2.3 使用示例

准备json数据

{
  "store": {
    "book": [
      {
        "category": "Java",
        "author": "张三",
        "title": "Java从入门到放弃",
        "price": 88.6
      },
      {
        "category": "Spring",
        "author": "Pack",
        "title": "Spring从入门到精通",
        "price": 99.8
      },
      {
        "category": "Java",
        "author": "李四",
        "title": "多线程并发编程",
        "isbn": "1-9527-6688-9",
        "price": 66.9
      },
      {
        "category": "Spring",
        "author": "Pack",
        "title": "Spring Boot3实战案例100讲",
        "isbn": "6-9527-7799-2",
        "price": 70
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 666
    }
  },
  "expensive": 10
}

层级格式如下:

接下来,我们将在代码中通过jsonpath来操作上面的json数据。

读取json内容

String json = new ClassPathResource("data.json")
  .getContentAsString(StandardCharsets.UTF_8) ;

下面都将基于上面读取到的json数据进行操作。

获取所有图书的作者

List<String> list = JsonPath.parse(json).read("$.store.book[*].author");
System.err.println("Authors: " + list) ;
// 输出结果
Authors: ["张三","Pack","李四","Pack"]

获取所有作者

List<String> list = JsonPath.parse(json).read("$..author") ;
System.err.println("Authors: " + list) ;
// 输出结果
Authors: ["张三","Pack","李四","Pack"]

获取store节点下的所有数据

Object result = JsonPath.parse(json).read("$.store.*") ;
System.err.println(result) ;

输出结果如下:

类型是:net.minidev.json.JSONArray

获取所有价格price

/**获取store节点下的所有price*/
List<Double> prices = JsonPath.parse(json).read("$.store..price") ;
System.err.println(prices) ;
// 输出结果
[88.6,99.8,66.9,70,666]

获取指定索引的书

/**获取第三本书*/
Object result = JsonPath.parse(json).read("$..book[2]") ;
System.err.println(result) ;
/**输出结果; 类型:net.minidev.json.JSONArray*/
[{"category":"Java","author":"李四","title":"多线程并发编程","isbn":"1-9527-6688-9","price":66.9}]


result = JsonPath.parse(json).read("$..book[0,1]") ;
System.err.println(result) ;
// 输出结果
[
  {"category":"Java","author":"张三","title":"Java从入门到放弃","price":88.6},
  {"category":"Spring","author":"Pack","title":"Spring从入门到精通","price":99.8}
]

所有带有ISBN编号的书

/**所有带有ISBN编号的书*/
Object result = JsonPath.parse(json).read("$..book[?(@.isbn)]") ;
System.err.println(result) ;
// 输出结果
[
  {"category":"Java","author":"李四","title":"多线程并发编程","isbn":"1-9527-6688-9","price":66.9},
  {"category":"Spring","author":"Pack","title":"Spring Boot3实战案例100讲","isbn":"6-9527-7799-2","price":70}
]

获取所有价格小于70元的图书

/**获取所有价格小于70元的图书*/
Object result = JsonPath.parse(json).read("$.store.book[?(@.price < 70)]") ;
System.err.println(result) ;
// 输出结果
[
  {"category":"Java","author":"李四","title":"多线程并发编程","isbn":"1-9527-6688-9","price":66.9}
]

获取图书的个数

// 获取图书的个数
Integer count = JsonPath.parse(json).read("$..book.length()") ;
System.err.println(count) ;
// 输出结果
4

自定义过滤条件

import static com.jayway.jsonpath.Criteria.where;
import static com.jayway.jsonpath.Filter.filter;
// 自定义filter
Filter cheapFictionFilter = filter(
    where("category").is("Java").and("price").lte(70D)
  );
List<Map<String, Object>> books = JsonPath.parse(json).read("$.store.book[?]", cheapFictionFilter);
System.err.println(books) ;
// 输出结果
[
  {"category":"Java","author":"李四","title":"多线程并发编程","isbn":"1-9527-6688-9","price":66.9}
]

修改数据

// 修改数据
String newJson = JsonPath.parse(json)
  .set("$['store']['book'][0]['author']", "pack_xg")
  .jsonString();
System.out.println(newJson) ;

输出结果:

图片图片

责任编辑:武晓燕 来源: Spring全家桶实战案例源码
相关推荐

2021-08-05 23:04:51

iPhone手机定位

2010-05-25 11:41:36

数据中心布线问题

2010-09-16 11:07:28

裁员

2019-04-08 08:25:48

代码开发工具

2019-07-16 13:02:26

BugDebug代码

2023-02-28 17:27:02

分库分表中间件

2019-06-17 05:03:37

memcache内核架构

2022-07-11 07:36:36

缓存缓存雪崩缓存击穿

2023-08-06 12:50:19

机器人AI

2010-03-05 08:54:14

Windows 7试用版升级

2022-02-18 18:00:00

数字人人工智能冬奥黑科技

2021-07-15 07:23:25

MySQL故障索引

2019-04-01 05:02:48

搜索架构检索

2014-11-12 09:58:48

2014-11-04 10:02:33

2021-03-19 09:55:15

Linuxshell命令

2020-05-07 16:08:28

Linuxshell命令

2021-10-11 07:46:50

ScalaJVM语言

2010-05-18 15:36:59

IIS服务器

2019-10-11 11:00:53

Nginx神器前端
点赞
收藏

51CTO技术栈公众号