Java 第三方包-Json 处理

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{
//...
/**
* Json path select
*
* @param jpath json path express
* @param useStandard use standard mode(default: false)
* @param cacheJpath cache json path parsing results
*/
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);

//第一本书title
ONode title = o.select("$.store.book[0].title");
System.out.println("title=::" + title);

//price大于10元的book
ONode list = o.select("$.store.book[?(price > 10)]");
System.out.println("price大于10元的book=::" + list);

//price大于10元的title
ONode list2 = o.select("$.store.book[?(price > 10)].title");
System.out.println("price大于10元的title=::" + list2);

//category(类别)为科幻的book
ONode list3 = o.select("$.store.book[?(category == '科幻')]");
System.out.println("category(类别)为科幻的book=::" + list3);


//bicycle的所有属性值
ONode values = o.select("$.store.bicycle.*");
System.out.println("bicycle的所有属性值=::" + values);


//bicycle的color和price属性值
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]