问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

JsonPath实战

创作时间:
作者:
@小白创作中心

JsonPath实战

引用
CSDN
1.
https://blog.csdn.net/lonelymanontheway/article/details/131384532

JsonPath是一种强大的工具,用于从JSON文档中提取所需的部分内容。它提供了类似正则表达式的语法,使得解析JSON文档变得简单而高效。本文将通过实战案例,详细介绍JsonPath的基本使用方法、表达式语法、函数支持以及进阶用法,帮助开发者快速掌握这一实用工具。

概述

JsonPath,GitHub是一种简单的方法来提取给定JSON文档的部分内容,提供类似正则表达式的语法来解析JSON文档。

特性

入门

引入如下Maven依赖:


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

基本使用:


JsonPath.read("", "");

需要传入两个String类型的参数,第一个参数为一个JSON String,第二个参数为JsonPath表达式。对应的源码为:


public static <T> T read(String json, String jsonPath, Predicate... filters) {
    return (new ParseContextImpl()).parse(json).read(jsonPath, filters);
}

第三个参数Predicate,表示谓词,在进阶部分会详细讲解。
查看
com.jayway.jsonpath.JsonPath
源码,不难发现,第一个参数可以替换成Object、File、URL、InputStream类型的JSON,即可以直接读取一个JSON文件或网络资源等。
返回类型可以是用泛型定义的任意对象(
T
),也可以是一个DocumentContext(用得不多,可以直接忽略)。

JsonPath表达式

从上面的简介,不难得知,使用好JsonPath的基础条件是熟悉JsonPath表达式:

  • JsonPath中的根成员对象始终称为
    $
    ,无论是对象JSON Object还是数组JSON Array
  • JsonPath表达式支持点表示法
  • 也支持括号表示法,繁琐,不建议使用
  • 解析JSON Array时,支持数组表示法,索引从0开始
  • 数组表示法,和Python 数组语法几乎没有差别
  • 表示所有节点
  • ..
    表示选择所有符合条件的节点
  • ?()
    表示过滤操作
  • @
    表示当前节点
    如何校验JsonPath表达式的合法性呢?

JsonPath.compile("$..");

使用IDEA的话,编译器会给出warning,执行mvn compile可以成功。运行这一行代码,JsonPath给出报错:
InvalidPathException: Path must not end with a '.' or '..'

函数支持

函数可以在路径的尾部调用,函数的输出是路径表达式的输出,该函数的输出是由函数本身所决定的。
函数 描述 输出
min() 返回数值类型数组的最小值 Double
max() 返回数值类型数组的最大值 Double
avg() 返回数值类型数组的平均值 Double
stddev() 返回数值类型数组的标准偏差值 Double
length() 返回数值类型数组的长度 Integer

过滤器运算符

?()
,表示过滤器,用于筛选数组的逻辑表达式。一个典型的过滤器将是
[?(@.age > 18)]

@
表示正在处理的当前项目。可使用逻辑运算符
&&

||
来创建更复杂的过滤器。字符串文字必须用单引号或双引号括起来:
[?(@.color == 'blue')]

[?(@.color == "blue")]

操作符 描述
== left等于right(注意1不等于’1’)
!= 不等于
< 小于
<= 小于等于

大于
= 大于等于
=~ 匹配正则表达式[?(@.name =~ /foo.*?/i)]
in 左边存在于右边 [?(@.size in [‘S’, ‘M’])]
nin 左边不存在于右边
size 数组或字符串长度
empty 数组或字符串为空

实战

示例JSON文档:


{
  "store": {
    "book": [
      {
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      {
        "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
}

很简单的一个JSON文档,有两个键值对,其中store表示商场,卖book和bicycle;expensive=10。
$.store.book[0].title
表示获取第一本书的标题,测试代码:


log.info(JsonPath.read(jsonStr, "$.store.book[0].title"));

输出:
Sayings of the Century

使用括号表示法,
$['store']['book'][0]['title']
,输出同样是
Sayings of the Century

$..book.length()
表示获取book这个Array的个数,输出2,测试代码略。
$..book[0,1]
表示获取第一、二两本书。
$..book[-2:]
表示获取最后两本书。
$..book[:1]
表示获取从索引0开始的书籍,索引1不算在内。
$..book[1:2]
表示获取从索引1开始的书籍,索引2不算在内。
$..book[1:]
表示获取第二本(索引1开始)到最后一本书。
$.store.book[*].author
表示获取所有book的作者,输出是一个列表。使用
..
的话,
$..author
也表示获取所有作者,输出列表。
$..book[?(@.isbn)]
表示获取JSON中book Array里包含isbn编号的书。
$.store.book[?(@.isbn)].author
表示获取JSON中book Array里包含isbn编号的书的作者。
$.store.book[?(@.price < 10)]
表示获取JSON中book Array里售价低于10的书。
$..book[?(@.price < $['expensive'])]
表示获取JSON中book Array里售价低于
expensive
的书。
支持的常用表达式
JsonPath 描述
$ 根节点
@ 当前节点
.or[] 子节点
.. 选择所有符合条件的节点

  • 所有节点
    [] 迭代器标示,如数组下标
    [,] 支持迭代器中做多选
    [start:end:step] 数组切片运算符
    ?() 支持过滤操作
    () 支持表达式计算

进阶

Exception

以json-path-2.9.0版本为例,共定义8个Exception:

  • InvalidCriteriaException
  • InvalidJsonException
  • InvalidModificationException
  • InvalidPathException
  • JsonPathException
  • PathNotFoundException
  • ValueCompareException
  • EvaluationAbortException
  • MappingException

谓词

谓词,谓语,也有翻译成断言的,即Predicate,JsonPath中的过滤器谓词有三种:

  • 内联谓词
  • 过滤器谓词
  • 自定义谓词

内联谓词


List<Map<String, Object>> books =  JsonPath.parse(json).read("$.store.book[?(@.price < 10)]");

可使用
&&

||
结合多个谓词
[?(@.price < 10 && @.category == 'fiction')]
。使用
!
否定一个谓词
[?(!(@.price < 10 && @.category == 'fiction'))]

过滤谓词

使用Filter API构建:


import static com.jayway.jsonpath.JsonPath.parse;
import static com.jayway.jsonpath.Criteria.where;
import static com.jayway.jsonpath.Filter.filter;
Filter filter = filter(
   where("category").is("fiction").and("price").lte(10D)
);
List<Map<String, Object>> books = parse(json).read("$.store.book[?]", filter);

占位符
?
为路径中的过滤器。当提供多个过滤器时,它们按照占位符数量与提供的过滤器数量相匹配的顺序应用。可以在一个过滤器操作
[?, ?]
中指定多个谓词占位符,这两个谓词都必须匹配。
过滤器也可以与
OR

AND
一起使用


Filter fooOrBar = filter(where("foo").exists(true)).or(where("bar").exists(true));
Filter fooAndBar = filter(where("foo").exists(true)).and(where("bar").exists(true));

自定义谓词


Predicate booksWithIsbn = new Predicate() {
    @Override
    public boolean apply(PredicateContext ctx) {
        return ctx.item(Map.class).containsKey("isbn");
    }
};
List<Map<String, Object>> books = reader.read("$.store.book[?].isbn", List.class, booksWithIsbn);

Configuration

Option

源码为
com.jayway.jsonpath.Option
,枚举类:

  • DEFAULT_PATH_LEAF_TO_NULL:当检索不到时返回null对象,否则如果不配置这个,会直接抛出异常PathNotFoundException
  • ALWAYS_RETURN_LIST:总是返回list,即便是一个确定的非list类型,也会被包装成list
  • AS_PATH_LIST:返回path
  • SUPPRESS_EXCEPTIONS:不抛出异常,需要判断如下:
  • ALWAYS_RETURN_LIST开启,则返回空list
  • ALWAYS_RETURN_LIST关闭,则返回null
  • REQUIRE_PROPERTIES:如果设置,则不允许使用通配符,比如
    $[*].b
    会抛出PathNotFoundException异常。

SPI

SPI是

cache

对应于源码

json

mapper

参考

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号