Jayway JsonPath介绍

JsonPath是一种用于在JSON数据结构中提取数据的语言,类似于XPath在XML中的作用。它提供了多种操作符和函数,如$.store.book[0].title用于选取第一本书的标题,以及过滤表达式[?(@.price<10)]来获取价格低于10的书籍。JaywayJsonPath是JsonPath的Java实现,支持配置选项如DEFAULT_PATH_LEAF_TO_NULL,ALWAYS_RETURN_LIST等,以及保存和修改JSON值的功能。此外,JsonPath还支持自定义谓词和不同类型的JsonProvider。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

XML的一个经常强调的优点是可以使用大量工具来分析,转换和有选择地从XML文档中提取数据,XPath是这些功能强大的工具之一。jsonPath类似Xpath,可以在json数据结构中进行分析。

对比XPath和JsonPath表达式如下:

XPathJSONPathDescription
/$the root object/element
.@the current object/element
/. or []child operator
..n/aparent operator
//..recursive descent. JSONPath borrows this syntax from E4X.
**wildcard. All objects/elements regardless their names.
@n/aattribute access. JSON structures don't have attributes.
[][]subscript operator. XPath uses it to iterate over element collections and for predicates. In Javascript and JSON it is the native array operator.
|[,]Union operator in XPath results in a combination of node sets. JSONPath allows alternate names or array indices as a set.
n/a[start:end:step]array slice operator borrowed from ES4.
[]?()applies a filter (script) expression.
n/a()script expression, using the underlying script engine.
()n/agrouping in Xpath

Jayway JsonPath是Stefan Goessner JsonPath 的java版本实现,

Jayway JsonPath功能介绍

1、JsonPath 表达式可以用 . 或者 [] 表示:

$.store.book[0].title
或者
$['store']['book'][0]['title']

 2、操作符:

OperatorDescription
$The root element to query. This starts all path expressions.
@The current node being processed by a filter predicate.
*Wildcard. Available anywhere a name or numeric are required.
..Deep scan. Available anywhere a name is required.
.<name>Dot-notated child
['<name>' (, '<name>')]Bracket-notated child or children
[<number> (, <number>)]Array index or indexes
[start:end]Array slice operator
[?(<expression>)]Filter expression. Expression must evaluate to a boolean value.

3、函数:

FunctionDescriptionOutput
min()Provides the min value of an array of numbersDouble
max()Provides the max value of an array of numbersDouble
avg()Provides the average value of an array of numbersDouble
stddev()Provides the standard deviation value of an array of numbersDouble
length()Provides the length of an arrayInteger
sum()Provides the sum value of an array of numbersDouble

4、过滤器:

OperatorDescription
==left is equal to right (note that 1 is not equal to '1')
!=left is not equal to right
<left is less than right
<=left is less or equal to right
>left is greater than right
>=left is greater than or equal to right
=~left matches regular expression [?(@.name =~ /foo.*?/i)]
inleft exists in right [?(@.size in ['S', 'M'])]
ninleft does not exists in right
subsetofleft is a subset of right [?(@.sizes subsetof ['S', 'M', 'L'])]
anyofleft has an intersection with right [?(@.sizes anyof ['M', 'L'])]
noneofleft has no intersection with right [?(@.sizes noneof ['M', 'L'])]
sizesize of left (array or string) should match right
emptyleft (array or string) should be empty

5、示例:

{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            },
            {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            },
            {
                "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
}

 JsonPath表达式:

JsonPath (click link to try)Result
$.store.book[*].authorThe authors of all books
$..authorAll authors
$.store.*All things, both books and bicycles
$.store..priceThe price of everything
$..book[2]The third book
$..book[-2]The second to last book
$..book[0,1]The first two books
$..book[:2]All books from index 0 (inclusive) until index 2 (exclusive)
$..book[1:2]All books from index 1 (inclusive) until index 2 (exclusive)
$..book[-2:]Last two books
$..book[2:]Book number two from tail
$..book[?(@.isbn)]All books with an ISBN number
$.store.book[?(@.price < 10)]All books in store cheaper than 10
$..book[?(@.price <= $['expensive'])]All books in store that are not "expensive"
$..book[?(@.author =~ /.*REES/i)]All books matching regex (ignore case)
$..*Give me every thing
$..book.length()The number of books

Jayway JsonPath使用

 1、执行jsonPath表达式:

String json = "...";

List<String> authors = JsonPath.read(json, "$.store.book[*].author");

如果需要多次执行,避免每次读重新解析json,可以通过如下方式:

String json = "...";
Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);

String author0 = JsonPath.read(document, "$.store.book[0].author");
String author1 = JsonPath.read(document, "$.store.book[1].author");

或者:(推荐这种写法)

String json = "...";

ReadContext ctx = JsonPath.parse(json);
List<String> authorsOfBooksWithISBN = ctx.read("$.store.book[?(@.isbn)].author");

2、返回值:

 JsonPath将自动尝试将结果强制转换为调用者期望的类型,如果出错将报出异常:

//Will throw an java.lang.ClassCastException    
List<String> list = JsonPath.parse(json).read("$.store.book[0].author")

//Works fine
String author = JsonPath.parse(json).read("$.store.book[0].author")

1)当jsonPath表示为下列不确定的,则返回list:

  • .. :全局匹配
  • ?(<expression>) : 过滤表达式
  • [<number>, <number> (, <number>)] :多索引

2)当表达式明确时,可以通过设置MappingProvider返回指定类型:

默认情况下,MappingProvider SPI提供了一个简单的对象映射器,当指定所需的返回类型时,MappingProvider将尝试执行映射。例如下面示例演示了Long和Date之间的映射。

String json = "{\"date_as_long\" : 1411455611975}";
Date date = JsonPath.parse(json).read("$['date_as_long']", Date.class);

如果将JsonPath配置为使用JacksonMappingProvider或GsonMappingProvider,您甚至可以将JsonPath输出直接映射到POJO。

Configuration conf = Configuration.builder()
                                  .jsonProvider(new GsonJsonProvider())
                                  .build();
Book book = JsonPath.using(conf).parse(json).read("$.store.book[0]", Book.class);

3)使用TypeRef:

TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {};
List<String> titles = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[*].title", typeRef);

3、配置:

[
   {
      "name" : "john",
      "gender" : "male"
   },
   {
      "name" : "ben"
   }
]

1)DEFAULT_PATH_LEAF_TO_NULL:

默认JsonPath表达式在对应的json中找不到数据时会报空指针异常,配置该选项后,找不到的会返回null。

Configuration conf = Configuration.defaultConfiguration();

//Works fine
String gender0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");
//PathNotFoundException thrown
String gender1 = JsonPath.using(conf).parse(json).read("$[1]['gender']");

Configuration conf2 = conf.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);

//Works fine
String gender0 = JsonPath.using(conf2).parse(json).read("$[0]['gender']");
//Works fine (null is returned)
String gender1 = JsonPath.using(conf2).parse(json).read("$[1]['gender']");

2)ALWAYS_RETURN_LIST:

配置后JsonPath始终返回list,即使表达式是一个明确的。

Configuration conf = Configuration.defaultConfiguration();

//ClassCastException thrown
List<String> genders0 = JsonPath.using(conf).parse(json).read("$[0]['gender']");

Configuration conf2 = conf.addOptions(Option.ALWAYS_RETURN_LIST);

//Works fine
List<String> genders0 = JsonPath.using(conf2).parse(json).read("$[0]['gender']");

3)SUPPRESS_EXCEPTIONS

默认Jayway JsonPath在执行jsonPath时会报错异常,配置后异常将被抑制。

  • 如果同时指定ALWAYS_RETURN_LIST:返回空list;
  • 没有制定ALWAYS_RETURN_LIST is NOT:返回null;

4)REQUIRE_PROPERTIES

禁止通配符,比如 $[*].b,会抛出 PathNotFoundException 异常。

5)AS_PATH_LIST

JsonPath可以返回Path或Value。值是默认值,也是上面所有示例返回的值。可以通过该选项让其返回路径。

Configuration conf = Configuration.builder()
   .options(Option.AS_PATH_LIST).build();

List<String> pathList = using(conf).parse(json).read("$..author");

assertThat(pathList).containsExactly(
    "$['store']['book'][0]['author']",
    "$['store']['book'][1]['author']",
    "$['store']['book'][2]['author']",
    "$['store']['book'][3]['author']");

4、保存/修改值:

String newJson = JsonPath.parse(json).set("$['store']['book'][0]['author']", "Paul").jsonString();

5、谓词(Predicates):

主要是filter predicate。有很多种方法实现,例如:

1)Inline Predicates

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

/**
*You can use && and || to combine multiple predicates [?(@.price < 10 && @.category == *'fiction')] , [?(@.category == 'reference' || @.price > 10)].
*
*You can use ! to negate a predicate [?(!(@.price < 10 && @.category == 'fiction'))].
*/

2)filter predicates:

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


//Filters can also be combined with 'OR' and '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)
);

:JsonPath中的占位符和路径中的过滤器要相互匹配。如果提供了多个过滤器,则会按占位符数量必须与提供的过滤器数量匹配的顺序应用它们。您可以在一个过滤器操作[?,?]中指定多个谓词占位符,两个谓词必须匹配。

3)Roll your own

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);

6、JsonProvider SPI:

Jayway JsonPath提供了一下json provider:

Configuration.setDefaults(new Configuration.Defaults() {

    private final JsonProvider jsonProvider = new JacksonJsonProvider();
    private final MappingProvider mappingProvider = new JacksonMappingProvider();
      
    @Override
    public JsonProvider jsonProvider() {
        return jsonProvider;
    }

    @Override
    public MappingProvider mappingProvider() {
        return mappingProvider;
    }
    
    @Override
    public Set<Option> options() {
        return EnumSet.noneOf(Option.class);
    }
});

注:JacksonJsonProvider requires com.fasterxml.jackson.core:jackson-databind:2.4.5 and the GsonJsonProvider requires com.google.code.gson:gson:2.3.1 on your classpath.

我们在解析json时,通常也会判断值得类型是object还是array,可以使用如下方法:

Configuration conf = Configuration.builder().options(Option.AS_PATH_LIST).build();
ReadContext ctx = JsonPath.using(conf).parse(json1_schema);
List<String> requiredPathList = ctx.read("$..required");

for (String path : requiredPathList) {
    //TODO 判断required的正确性:如果requiredValueList中元素不是array则continue
    String replace = path.replace("$['", "").replace("']['", ",").replace("']", "");
    Object object = requiredValueList.get(requiredIndex);
    requiredIndex++;
    if(object instanceof net.minidev.json.JSONArray) {
        //System.out.println("        "+replace+","+object.toString());
        pathRequiredMap.put(replace, JSONArray.parseArray(object.toString()));
    }
}

7、Cache SPI:

Jayway JsonPath提供了一下cache:

  • com.jayway.jsonpath.spi.cache.LRUCache (default, thread safe)
  • com.jayway.jsonpath.spi.cache.NOOPCache (no cache)
CacheProvider.setCache(new Cache() {
    //Not thread safe simple cache
    private Map<String, JsonPath> map = new HashMap<String, JsonPath>();

    @Override
    public JsonPath get(String key) {
        return map.get(key);
    }

    @Override
    public void put(String key, JsonPath jsonPath) {
        map.put(key, jsonPath);
    }
});

参考:https://zju-cy.github.io/2019/07/07/JsonPath

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

赶路人儿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值