场景
以前工作中,习惯于将对象转换为 json。并一直感觉这种转换非常的方便。
因为借助 fastjson, gjson, jackson 等工具就是一个方法就搞定。
以前写一些数据的抓取,我也会写一大堆代码,去构建这个对象。
后来知道有 mongo 这种文档型数据库,觉得也挺方便。
但是 xml 有 xmlPath, 我为什么一直都没有想到 json 有 json path 呢??
问题
比如 google 返回的 json 如下
[[["Hello, Li Yinhe. ","你好啊,李银河。",null,null,3],["Beautiful stories are always too far away. ","美丽的故事总是太遥远。",null,null,3],["Grass along the Qingqing River, seeing the Vega.","青青河边草,遥看织女星。",null,null,3],[null,null,null,"Nǐ hǎo a, lǐ yínhé. Měilì de gùshì zǒng shì tài yáoyuǎn. Qīngqīng hé biān cǎo, yáo kàn zhīnǚxīng."]],null,"zh-CN",null,null,[["你好啊,李银河。",null,[["Hello, Li Yinhe.",0,true,false]],[[0,8]],"你好啊,李银河。",0,0],["美丽的故事总是太遥远。",null,[["Beautiful stories are always too far away.",0,true,false],["Beautiful story always too far away.",0,true,false]],[[0,11]],"美丽的故事总是太遥远。",0,0],["青青河边草,遥看织女星。",null,[["Grass along the Qingqing River, seeing the Vega.",0,true,false],["青青河边草, very thick Vega.",0,true,false]],[[0,12]],"青青河边草,遥看织女星。",0,0]],1,null,[["zh-CN"],null,[1],["zh-CN"]]]
我构建了半天都感觉这个对象不一般,而且第一个数组是会动态变化的。
我关心的字段信息,只是翻译后的字段信息。
然后就去查了一下,发现了 json path。
核心方法介绍
JsonPath表达式始终引用JSON结构,其方式与XPath表达式与XML文档结合使用的方式相同。
JsonPath中的“根成员对象”始终称为 $
,无论它是对象还是数组。
访问
可以使用点访问符号
$.store.book[0].title
也可以使用中括号访问
$['store']['book'][0]['title']
操作
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. |
函数
可以在路径的尾端调用函数 - 函数的输入是路径表达式的输出。
功能输出由功能本身决定。
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 |
过滤运算符
过滤器是用于过滤数组的逻辑表达式。
典型的过滤器是 [?(@.age > 18)]
,其中@表示当前正在处理的项目。
可以使用逻辑运算符 &&
和 ||
创建更复杂的过滤器。
字符串文字必须用单引号或双引号括起来 ([?(@.color == 'blue')]
or [?(@.color == "blue")]
)。
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 |
使用 JsonPath
maven 引入
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>
入门案例
{"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 (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 |
读取文档
使用JsonPath最简单最直接的方法是通过静态读取API。
List<String> authors = JsonPath.read(json, "$.store.book[*].author");
个人实战
获取所有中文的翻译
很简单的一句话即可:
List<String> stringList = JsonPath.read(json, "$.[0][:-1][0]");
信息如下:
Hello, Li Yinhe.
Beautiful stories are always too far away.
Grass along the Qingqing River, seeing the Vega.
性能优化
如果我们需要提取 json 中的多个数值,可以首先初始化一下 context,然后再做处理。
final String json = "{}";
// 避免多次解析
final ReadContext jsonContext = JsonPath.parse(json);
// 根据路径获取指定的值
Object value = jsonContext.read(jsonPath);
jsonpath 报错的问题
发现 jsonPath 在处理值的时候,如果值不存在,会直接报错。
怎么解决呢?
解决方案
Configuration configuration = Configuration.builder().options(Option.DEFAULT_PATH_LEAF_TO_NULL).build();
val value = JsonPath.parse(document, configuration).read("$.root.family.hasChild"));
这样就不会报错了。
json 系列
字符串
二进制
其他
参考资料
https://www.null123.com/question/detail-2064645.html