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

JsonPath实战

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

JsonPath实战

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

概述

JsonPath是一种简单的方法来提取给定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号