1. Snack3 Snack3 是一个支持 JSONPath 的 JSON 框架。JSONPath 是一个很强大的功能,也可以在 Java 框架中当作对象查询语言(OQL)来使用。 Snack3 借签了 Javascript 所有变量由 var 申明,及 Xml dom 一切都是 Node 的设计。其下一切数据都以 ONode 表示,ONode 也即 One node 之意,代表任何类型,也可以转换为任何类型。
1.1. 引用 1 2 3 4 5 <dependency > <groupId > org.noear</groupId > <artifactId > snack3</artifactId > <version > 3.2.31</version > </dependency >
1.2. 接口 默认使用缓存 JSONPath 解析对象,可提高性能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ONode { public ONode select (String jpath, boolean useStandard, boolean cacheJpath) { return JsonPath.eval(this , jpath, useStandard, cacheJpath); } public ONode select (String jpath, boolean useStandard) { return select(jpath, useStandard, true ); } public ONode select (String jpath) { return select(jpath, false ); } }
1.3. 支持语法
基础操作
说明
$
表示根元素
@
当前节点(做为过滤表达式的谓词使用)
*
通用配配符,可以表示一个名字或数字
..
可以理解为递归搜索
.<name>
表示一个子节点
['<name>' (, '<name>')]
表示一个或多个子节点
[<number> (, <number>)]
表示一个或多个数组下标(负号为倒数)
[start:end]
数组片段,区间为 [start,end), 不包含 end(负号为倒数)
其也支持逻辑处理,可以使用布尔表达式进行过滤,逻辑操作符与字段要用空隔隔开,格式为 [?(<expression>)]
逻辑操作符
说明
==
left 等于 right(注意 1 不等于 ‘1’)
!=
不等于
<
小于
<=
小于等于
>
大于
>=
大于等于
=~
匹配正则表达式 [?(@.name =~ /foo.*?/i)]
in
左边存在于右边 [?(@.size in [‘S’, ‘M’])]
nin
左边不存在于右边
其还支持聚合函数
聚合函数
说明
min()
计算数字数组的最小值
max()
计算数字数组的最大值
avg()
计算数字数组的平均值
sum()
计算数字数组的汇总值
1.4. 示例 使用到的实体类
1 2 3 4 5 6 7 public static class Entity { public int id; public String name; public Object value; public Entity(int id, Object value) { this.id = id; this.value = value; } public Entity(String name) { this.name = name; } }
1. 读取对象的属性 1 2 3 4 5 Entity entity = new Entity (123 , new Object ());ONode n = ONode.load(entity);assert n.select("$.id" ).getInt() == 123 ;assert n.select("$.*" ).count() == 2 ;
2. 读取集合多个元素的某个属性 1 2 3 4 5 6 7 List<Entity> entities = new ArrayList <Entity>(); entities.add(new Entity ("hello" )); entities.add(new Entity ("world" )); ONode n = ONode.load(entities);List<String> names = n.select("$.name" ).toObject(List.class); assert names.size() == 2 ;
3. 返回集合中多个元素 1 2 3 4 5 6 7 8 List<Entity> entities = new ArrayList <Entity>(); entities.add(new Entity ("hello" )); entities.add(new Entity ("world" )); entities.add(new Entity ("java" )); ONode n = ONode.load(entities);List<Entity> result = n.select("$[1,2]" ).toObject((new ArrayList <Entity>() {}).getClass()); assert result.size() == 2 ;
4. 按范围返回集合的子集 1 2 3 4 5 6 7 8 List<Entity> entities = new ArrayList <Entity>(); entities.add(new Entity ("hello" )); entities.add(new Entity ("world" )); entities.add(new Entity ("java" )); ONode n = ONode.load(entities);List<Entity> result = n.select("$[0:2]" ).toObject((new ArrayList <Entity>(){}).getClass()); assert result.size() == 2 ;
5. 返回逻辑处理后的自子集 1 2 3 4 5 6 7 8 9 List<Entity> entities = new ArrayList <Entity>(); entities.add(new Entity (1001 , "hello" )); entities.add(new Entity (1002 , "world" )); entities.add(new Entity (1003 , "java" )); entities.add(new Entity (1004 , null )); ONode n = ONode.load(entities);ONode rst = n.select("$[?($.id in [1001,1002])]" );assert rst.count() == 2 ;
6. 对象修改 1 2 3 4 5 6 7 8 9 10 11 Entity entity = new Entity (1001 , "hello" );ONode n = ONode.load(entity);assert n.select("$[?(id == 1001)]" ).isObject();assert n.select("$[?(id == 1002)]" ).isNull();n.select("$" ).set("id" ,123456 ); assert n.get("id" ).getInt() == 123456 ;n.get("value" ).add(1 ).add(2 ).add(3 ); assert n.get("value" ).count() == 3 ;
7. 递归查询 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Map root = Collections.singletonMap("company" , Collections.singletonMap("departs" , Arrays.asList( Collections.singletonMap("id" , 1001 ), Collections.singletonMap("id" , 1002 ), Collections.singletonMap("id" , 1003 ) ) )); ONode n = ONode.load(root);List<Object> ids = n.select("$..id" ).toObject(List.class); assertEquals(3l , ids.size()); assertEquals(1001l , ids.get(0 )); assertEquals(1002l , ids.get(1 )); assertEquals(1003l , ids.get(2 ));
8. json 处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 String jsonStr = "{" + " \"store\": {" + " \"bicycle\": {" + " \"color\": \"red\"," + " \"price\": 19.95" + " }," + " \"book\": [" + " {" + " \"author\": \"刘慈欣\"," + " \"price\": 8.95," + " \"category\": \"科幻\"," + " \"title\": \"三体\"" + " }," + " {" + " \"author\": \"itguang\"," + " \"price\": 12.99," + " \"category\": \"编程语言\"," + " \"title\": \"go语言实战\"" + " }" + " ]" + " }" + "}" ; ONode o = ONode.load(jsonStr);ONode books = o.select("$.store.book" );System.out.println("books=::" + books); ONode titles = o.select("$.store.book.title" );System.out.println("titles=::" + titles); ONode title = o.select("$.store.book[0].title" );System.out.println("title=::" + title); ONode list = o.select("$.store.book[?(price > 10)]" );System.out.println("price大于10元的book=::" + list); ONode list2 = o.select("$.store.book[?(price > 10)].title" );System.out.println("price大于10元的title=::" + list2); ONode list3 = o.select("$.store.book[?(category == '科幻')]" );System.out.println("category(类别)为科幻的book=::" + list3); ONode values = o.select("$.store.bicycle.*" );System.out.println("bicycle的所有属性值=::" + values); ONode read = o.select("$.store.bicycle['color','price']" );System.out.println("bicycle的color和price属性值=::" + read);
打印结果
1 2 3 4 5 6 7 8 books=::[{"author" :"刘慈欣" ,"price" :8.95 ,"category" :"科幻" ,"title" :"三体" },{"author" :"itguang" ,"price" :12.99 ,"category" :"编程语言" ,"title" :"go语言实战" }] titles=::["三体" ,"go语言实战" ] title=::"三体" price大于10 元的book=::[{"author" :"itguang" ,"price" :12.99 ,"category" :"编程语言" ,"title" :"go语言实战" }] price大于10 元的title=::["go语言实战" ] category(类别)为科幻的book=::[{"author" :"刘慈欣" ,"price" :8.95 ,"category" :"科幻" ,"title" :"三体" }] bicycle的所有属性值=::["red" ,19.95 ] bicycle的color和price属性值=::["red" ,19.95 ]