场景
以前工作中,习惯于将对象转换为 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
