赞
踩
2021SC@SDUSC
正如XPath对XML的解析一样,JSONPath的定义,简单说来,就是对JSON文档的一种解析。通过JSONPath可以轻松的对JSON文档获取指定“路径”的数据,在繁杂的、肉眼难以阅读的json字符串中精准找到需要的部分。
有两个需要注意的点:
JSONPath的索引从0开始计数
JSONPath中字符串使用单引号表示
使用Fastjson中的JSONPath解析器,首先需要将json字符串转换成JSONObject类型的对象。然后调用JSONPath.eval()方法,获取指定的字符串。
package com.xiaobu.note.json.fastjson; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONPath; public class FastJsonDemo1 { public static void main(String[] args) { String jsonStr = "{ \"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,\"isbn\": \"0-553-21311-3\"" + "}],\"bicycle\": {\"color\": \"red\",\"price\": 19.95}}}"; // 先解析JSON数据为JSONObject,然后就能直接使用JSONPath了。 JSONObject jsonObject = JSON.parseObject(jsonStr); System.out.println("book数目:"+ JSONPath.eval(jsonObject, "$.store.book.size()") ); System.out.println("第一本书的title:"+JSONPath.eval(jsonObject,"$.store.book[0].title")); System.out.println("第一本书的category和author:"+JSONPath.eval(jsonObject,"$.store.book[0]['category','author']")); System.out.println("price>10的书:"+JSONPath.eval(jsonObject,"$.store.book[price>10]")); System.out.println("price>8的书的标题:"+JSONPath.eval(jsonObject,"$.store.book[price>8]")); System.out.println("price>7的书:"+JSONPath.eval(jsonObject,"$.store.book[price>7]")); System.out.println("price>7的书的标题:"+JSONPath.eval(jsonObject,"$.store.book[price>7].title")); //不带单引号会出现Exception in thread "main" java.lang.UnsupportedOperationException 异常 System.out.println("书的标题为Sayings of the Century:"+JSONPath.eval(jsonObject,"$.store.book[title='Sayings of the Century']")); System.out.println("bicycle的所有属性:"+JSONPath.eval(jsonObject,"$.store.bicycle.*")); System.out.println("bicycle:"+JSONPath.eval(jsonObject,"$.store.bicycle")); } }
结果:
book数目:2
第一本书的title:Sayings of the Century
第一本书的category和author:[reference, Nigel Rees]
price>10的书:[{"author":"Evelyn Waugh","price":12.99,"isbn":"0-553-21311-3","category":"fiction","title":"Sword of Honour"}]
price>8的书的标题:[{"author":"Evelyn Waugh","price":12.99,"isbn":"0-553-21311-3","category":"fiction","title":"Sword of Honour"}]
price>7的书:[{"author":"Nigel Rees","price":8.95,"category":"reference","title":"Sayings of the Century"}, {"author":"Evelyn Waugh","price":12.99,"isbn":"0-553-21311-3","category":"fiction","title":"Sword of Honour"}]
price>7的书的标题:[Sayings of the Century, Sword of Honour]
书的标题为Sayings of the Century:[{"author":"Nigel Rees","price":8.95,"category":"reference","title":"Sayings of the Century"}]
bicycle的所有属性:[red, 19.95]
bicycle:{"color":"red","price":19.95}
可以看到,在这段难以阅读的json字符串中,我们轻松取到了书籍数目、第一本书的书名等关键信息。
这只是eval方法的用法,下面介绍一下这个类其他的几个关键方法的作用:
求值,静态方法
public static Object eval(Object rootObject, String path);
计算Size,Map非空元素个数,对象非空元素个数,Collection的Size,数组的长度。其他无法求值返回-1
public static int size(Object rootObject, String path);
是否包含,path中是否存在对象
public static boolean contains(Object rootObject, String path) { }
是否包含,path中是否存在指定值,如果是集合或者数组,在集合中查找value是否存在
public static boolean containsValue(Object rootObject, String path, Object value) { }
修改制定路径的值,如果修改成功,返回true,否则返回false
public static boolean set(Object rootObject, String path, Object value) {}
在数组或者集合中添加元素
public static boolean array_add(Object rootObject, String path, Object… values);
分析一下JSONPath中eval方法的作用机制。
public static Object eval(Object rootObject, String path) {
JSONPath jsonpath = compile(path);
return jsonpath.eval(rootObject);
}
这是我们调用的eval方法,可以看到它又调用了同名方法eval:
public Object eval(Object rootObject) {
if (rootObject == null) {
return null;
} else {
this.init();
Object currentObject = rootObject;
for(int i = 0; i < this.segments.length; ++i) {
currentObject = this.segments[i].eval(this, rootObject, currentObject);
}
return currentObject;
}
}
此时,可以看到再次调用了eval方法,我们再次跟进:
public Object eval(JSONPath path, Object rootObject, Object currentObject) { int size = JSONPath.SizeSegement.instance.eval(path, rootObject, currentObject);//获取rootObject的尺寸,即JSONObject对象数量 int start = this.start >= 0 ? this.start : this.start + size; int end = this.end >= 0 ? this.end : this.end + size;//获取起始位置和终止位置 int array_size = (end - start) / this.step + 1;//获取数组大小 if (array_size == -1) { return null; } else { List<Object> items = new ArrayList(array_size); for(int i = start; i <= end && i < size; i += this.step) { Object item = path.getArrayItem(currentObject, i); items.add(item);//遍历数组,将符合条件的Object对象添加到item中,作为结果返回 } return items; } }
显然,Fastjson做的工作就是将JSONObject对象层层遍历,通过我们给定的JSONPath路径,按照我们的解析规则将遍历后的结果放进一个List对象中并返回给调用者。由于事先确定了起始位置和终止位置,遍历过程中会减少很多次对不会出现在结果集中的数据的访问,大大加快了解析速度。这也是Fastjson速度快的原因——通过增加条件来减少对数据的访问。
使用JSONPath类提供的静态方法能够非常快速地对json字符串进行路径解析,将指定位置的json字符串以对象的形式返回,方便了系统的调用者。JSONPath与XPath的路径解析规则差不多,熟练使用这种解析方式,再用上Fastjson提供的静态方法,可以将在需要使用JSONPath的项目中将解析速度大大提升。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。