0
点赞
收藏
分享

微信扫一扫

Jayway JsonPath介绍

芝婵 2022-06-20 阅读 19

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

对比XPath和JsonPath表达式如下:

XPath

JSONPath

Description

/

$

the root object/element

.

@

the current object/element

/

. or []

child operator

..

n/a

parent operator

//

..

recursive descent. JSONPath borrows this syntax from E4X.

*

*

wildcard. All objects/elements regardless their names.

@

n/a

attribute 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/a

grouping in Xpath

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

  • github:​​https://github.com/json-path/JsonPath​​
  • 在线工具:​​http://jsonpath.herokuapp.com/​​

Jayway JsonPath功能介绍

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

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

 2、操作符:

Operator

Description

​$​

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、函数:

Function

Description

Output

min()

Provides the min value of an array of numbers

Double

max()

Provides the max value of an array of numbers

Double

avg()

Provides the average value of an array of numbers

Double

stddev()

Provides the standard deviation value of an array of numbers

Double

length()

Provides the length of an array

Integer

sum()

Provides the sum value of an array of numbers

Double

4、过滤器:

Operator

Description

==

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

in

left exists in right [?(@.size in ['S', 'M'])]

nin

left does not exists in right

subsetof

left is a subset of right [?(@.sizes subsetof ['S', 'M', 'L'])]

anyof

left has an intersection with right [?(@.sizes anyof ['M', 'L'])]

noneof

left has no intersection with right [?(@.sizes noneof ['M', 'L'])]

size

size of left (array or string) should match right

empty

left (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[*].author​​

The authors of all books

​​$..author​​

All authors

​​$.store.*​​

All things, both books and bicycles

​​$.store..price​​

The 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:

  • ​​JsonSmartJsonProvider​​ (default)
  • ​​JacksonJsonProvider​​
  • ​​JacksonJsonNodeJsonProvider​​
  • ​​GsonJsonProvider​​
  • ​​JsonOrgJsonProvider​​
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​​

 

 

 

 

 


举报

相关推荐

0 条评论