赞
踩
在一些特殊场景中,可能 一串json有几个甚至上万个节点,那么要去获取里面某一个节点或者说设置某个json指定key的值,那就非常麻烦了,一般我们是通过递归来进行获取,获取后还需要再通过递归进行遍历设置值,所以相当来说非常麻烦。是否有已有现成的工具进行设置呢?
注:使用当先请跳转到:注意点进行了解性能问题。
官网:https://goessner.net/articles/JsonPath/
github官网:https://github.com/json-path/JsonPath
jsonPath是一个非常强大的,可以通过规则、指定的格式获取或设置需要的json位置,通过jsonPath可以快速实现json自定义的位置获取或赋值。
过滤器是用于筛选数组的逻辑表达式。一个典型的过滤器将是[?(@.age > 18)],其中@表示正在处理的当前项目。可以使用逻辑运算符&&和||创建更复杂的过滤器。字符串文字必须用单引号或双引号括起来([?(@.color == 'blue')] 或者 [?(@.color == "blue")]).
操作符 | 描述 |
== | left等于right(注意1不等于'1') |
!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
=~ | 匹配正则表达式[?(@.name =~ /foo.*?/i)] |
in | 左边存在于右边 [?(@.size in ['S', 'M'])] |
nin | 左边不存在于右边 |
size | (数组或字符串)长度 |
empty | (数组或字符串)为空 |
引入java的POM坐标
- <dependency>
- <groupId>com.jayway.jsonpath</groupId>
- <artifactId>json-path</artifactId>
- <version>2.7.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 (点击链接测试) | 结果 |
$.store.book[*].author | 获取json中store下book下的所有author值 |
$..author | 获取所有json中所有author的值 |
$.store.* | 所有的东西,书籍和自行车 |
$.store..price | 获取json中store下所有price的值 |
$..book[2] | 获取json中book数组的第3个值 |
$..book[-2] | 倒数的第二本书 |
$..book[0,1] | 前两本书 |
$..book[:2] | 从索引0(包括)到索引2(排除)的所有图书 |
$..book[1:2] | 从索引1(包括)到索引2(排除)的所有图书 |
$..book[-2:] | 获取json中book数组的最后两个值 |
$..book[2:] | 获取json中book数组的第3个到最后一个的区间值 |
$..book[?(@.isbn)] | 获取json中book数组中包含isbn的所有值 |
$.store.book[?(@.price < 10)] | 获取json中book数组中price<10的所有值 |
$..book[?(@.price <= $['expensive'])] | 获取json中book数组中price<=expensive的所有值 |
$..book[?(@.author =~ /.*REES/i)] | 获取json中book数组中的作者以REES结尾的所有值(REES不区分大小写) |
$..* | 逐层列出json中的所有值,层级由外到内 |
$..book.length() | 获取json中book数组的长度 |
- String rule3 = FileTool.readFileString("D:\\workspace\\jsonpath_study\\src\\main\\java\\com.hong.test\\demo.json","UTF-8");
- List<String> authors = JsonPath.read(rule3, "$.store.book[*].author");
- System.out.println(Arrays.asList(authors));
结果
[["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]]
需要将下面的json,找到指定compType为http的节点,并且找到后,循环赋值到这个节点下面的chidren里面。比如
- {
-
- "compName":"xxx",
- "identifyName":"order",
- "compCode":"001",
- "compType":"http",
- "parentCompType":"service",
- "parentCompCode":"",
- "compIndex":"1",
- "children":[
- {
- "compName":"版本",
- "compType":"httpVersionNumber",
- "compValue":"1.0",
- "parentCompType":"http",
- "compIndex":1,
- "children":[
-
- ],
- "currentPosition":""
- },
- {
- "compName":"服务x",
- "compType":"httpInstanceCode",
- "compValue":"xx",
- "parentCompType":"http",
- "compIndex":2,
- "children":[
-
- ],
- "currentPosition":""
- },
- {
- "compName":"xx列表",
- "compType":"httpRequest",
- "compValue":"",
- "parentCompType":"http",
- "compIndex":3,
- "children":[
- {
- "compName":"用户名称",
- "compType":"reqParams",
- "compValue":"userName",
- "parentCompType":"httpRequest",
- "compIndex":1,
- "children":[
- {
- "compName":"x",
- "compType":"reqMapping",
- "compValue":"order.userName",
- "parentCompType":"reqParams",
- "compIndex":1,
- "children":[
-
- ],
- "currentPosition":""
- }
- ],
- "currentPosition":""
- }
-
- ] }
- ]
- }
- String rule2 = FileTool.readFileString("D:\\workspace\\jsonpath_study\\src\\main\\java\\com.hong.test\\b.json", "UTF-8");
- JSONArray array = JSONObject.parseArray(JsonPath.read(rule2, "$..children[?(@.compType=='http')]").toString());
- int i = 0;
- while (i < 10000) {
- i++;
- for (Object o : array) {
- JSONObject json = (JSONObject) o;
-
- rule2 = JsonPath.parse(rule2).set("$..children[?(@.compCode=='" + json.get("compCode") + "')].children", "aa").jsonString();
- }
- }
- System.out.println(rule2);
结果
- {
-
- "compName":"xxx",
- "identifyName":"order",
- "compCode":"001",
- "compType":"http",
- "parentCompType":"service",
- "parentCompCode":"",
- "compIndex":"1",
- "children":“aa”
- }
可以看到快速替换了,很方便。
上面为什么要用1万次,就是测试jsonPath的性能问题,可以发现,jsonpath如果在多个执行中会导致CPU突然间飙升20%~50%,这一点是需要注意的,如果你的json或者线上的环境本来cpu使用率就很高那就要注意是否符合你的场景,但是我这个json是非常非常长的,有一百多kb,一般情况下是不可能有这么长,所以还是需要根据自已的实际场景进行判断是否引用。切记 切记 切记
jsonPath底层也是通过递归的方式进行实现,有兴趣的同学可以进行研究底层源码。需要特别注意的是如果引用了jsonPath那么需要特别关注cpu的性能指标,jsonPath会在短时间内将执行的cpu突增20%~50%(大json),可能会导致cpu飙高,所以要特别注意是否适用当前场景。
参考地址:
https://zhuanlan.zhihu.com/p/30188199
http://www.ibloger.net/article/2329.html
https://www.leftso.com/blog/796.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。