1、json的组成
JSON是一个标记符序列。这套标记符包括:构造字符、字符串、数字和字面值(false, true, null)。
1.1 构造字符
六个构造字符:
左方括号 [
右方括号 ]
左大括号 {
右大括号 }
冒号 :
逗号 ,
1.2 JSON值
json值包括:对象、数组、字符串、字面值(true,false,null)
1.2.1 对象
由花括号括起来,逗号分割的成员构成,成员是字符串键和上面所说的JSON值构成
{"name":"jery", "age":18, "sex":"男"}
1.2.2 数组
由方括号括起来的一组JSON值构成
示例1:一组数字组成的数组
[1, 2, 3, 4, 5, 6, 7, 8]
示例2:一组对象组成的数组
[
{"name":"jery", "age":18, "sex":"男"},
{"name":"lina", "age":16, "sex":"女"}
]
1.2.3 字符串、数字和 字面值
下面示例中的name的值为字符串,age的值为数字,isStudent的值为false。
{
"name":"jery",
"age":4,
"isStudent":false
}
2、 JsonPath
很多时候我们拿到其他模块的json字符串,如果不存在共享的java实体类定义,可能会直接使用JsonObject之类的动态对象类承接这份数据。这时候对于很深的的属性取值是非常复杂的,例如:
public class JsonTest {
@Test
public void getJsonObjectValueTest() {
String json = "{\"a\":{\"b\":{\"c\":{\"d\":\"我是d的值\"}}}}";
System.out.println(getJsonObjectValue(json));
}
private String getJsonObjectValue(String jsonStr) {
JSONObject json = JSONObject.parseObject(jsonStr);
JSONObject a = json.getJSONObject("a");
if (a != null) {
JSONObject b = a.getJSONObject("b");
if (b != null) {
JSONObject c = b.getJSONObject("c");
if (c != null) {
return c.getString("d");
}
}
}
return null;
}
}
使用jsonpath可以变的简单:
@Test
public void getValueByPathTest() {
String json = "{\"a\":{\"b\":{\"c\":{\"d\":\"我是d的值\"}}}}";
Object value = JSONPath.compile("$.a.b.c.d").eval(json);
System.out.println(value);
}
2.1 基本语法
参考 https://github.com/alibaba/fastjson/wiki/JSONPath
FastJson 解析神器JsonPath 使用手册-CSDN博客
JSONPATH | 描述 |
$ | 根对象,例如$.name |
@ | 文档当前节点对象,类似于java 中的 this 字段 |
[num] | 数组访问,其中num是数字,可以是负数。例如$[0].leader.departments[-1].name |
[num0,num1,num2...] | 数组多个元素访问,其中num是数字,可以是负数,返回数组中的多个元素。例如$[0,3,-2,5] |
[start:end] | 数组范围访问,其中start和end是开始小表和结束下标,可以是负数,返回数组中的多个元素。例如$[0:5] |
[start:end :step] | 数组范围访问,其中start和end是开始小表和结束下标,可以是负数;step是步长,返回数组中的多个元素。例如$[0:5:2] |
[?(key)] | 对象属性非空过滤,例如$.departs[?(name)] |
[key > 123] | 数值类型对象属性比较过滤,例如$.departs[id >= 123],比较操作符支持=,!=,>,>=,<,<= |
[key = '123'] | 字符串类型对象属性比较过滤,例如$.departs[name = '123'],比较操作符支持=,!=,>,>=,<,<= |
[key like 'aa%'] | 字符串类型like过滤, 例如$.departs[name like 'sz*'],通配符只支持% 支持not like |
[key rlike 'regexpr'] | 字符串类型正则匹配过滤, 例如departs[name rlike 'aa(.)*'], 正则语法为jdk的正则语法,支持not rlike |
[key in ('v0', 'v1')] | IN过滤, 支持字符串和数值类型 例如: $.departs[name in ('wenshao','Yako')] $.departs[id not in (101,102)] |
[key between 234 and 456] | BETWEEN过滤, 支持数值类型,支持not between 例如: $.departs[id between 101 and 201] $.departs[id not between 101 and 201] |
length() 或者 size() | 数组长度。例如$.values.size() 支持类型java.util.Map和java.util.Collection和数组 |
keySet() | 获取Map的keySet或者对象的非空属性名称。例如$.val.keySet() 支持类型:Map和普通对象 不支持:Collection和数组(返回null) |
. | 属性访问,例如$.name |
.. | deepScan属性访问,例如$..name |
* | 对象的所有属性,例如$.leader.* |
['key'] | 属性访问。例如$['name'] |
['key0','key1'] | 多个属性访问。例如$['id','name'] |
- $:表示JSON数据的根对象。
- . 或 []:用于访问对象的属性或数组的元素。例如,
$.name
或 $[‘name’] 都可以访问根对象中的 ‘name’ 属性。 - …:表示递归下降,用于查找所有级别的属性。
- ?():应用一个过滤表达式来过滤数组中的元素。例如,
$?(@.age>18)
将选择所有年龄大于18的对象。 - []:在属性名或数组索引位置使用,表示选择所有元素。例如,
$.students[*].name
将选择所有学生的名字。 - -1、0、1、n:用作数组索引时,表示从最后一个元素开始计数。例如,
$.students[-1].name
将选择最后一个学生的名字。
2.1 关于JSONPath.eval中第三个参数ignoreNullValue
在jsonPath中,如果要获取的参数是列表中的元素(返回的是列表),会默认过滤掉null的取值,示例:
public void jsonTestDefaultIgnoreNull() {
String jsonStr = "{'store':{'book':[" +
"{'category':'reference','author':'Nigel Rees','title':'Sayings of the Century','price':8.95}," +
"null," +
"{'category':null,'author':'Evelyn Waugh','title':'Sword of Honour','price':12.99}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
JSONObject jsonObject = JSON.parseObject(jsonStr);
System.out.println("Book数目:" + JSONPath.eval(jsonObject, "$.store.book.size()"));
System.out.println("books:" + JSONPath.eval(jsonObject, "$.store.book"));
System.out.println("categories:" + JSONPath.eval(jsonObject, "$.store.book.category"));
System.out.println("categories:" + JSONPath.eval(jsonObject, "$.store.book[*].category"));
}
执行结果为(categories列表不包含第2个null book和第三个book的null categoriy:
Book数目:3
books:[{"author":"Nigel Rees","price":8.95,"category":"reference","title":"Sayings of the Century"},null,{"author":"Evelyn Waugh","price":12.99,"title":"Sword of Honour"}]
categories:["reference"]
categories:["reference"]
添加ignoreNullValue参数并设置为false后,返回的categories会包含后面两个book的null:
public void jsonTestNotIgnoreNull() {
String jsonStr = "{'store':{'book':[" +
"{'category':'reference','author':'Nigel Rees','title':'Sayings of the Century','price':8.95}," +
"null," +
"{'category':null,'author':'Evelyn Waugh','title':'Sword of Honour','price':12.99}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
JSONObject jsonObject = JSON.parseObject(jsonStr);
System.out.println("Book数目:" + JSONPath.eval(jsonObject, "$.store.book.size()", false));
System.out.println("books:" + JSONPath.eval(jsonObject, "$.store.book[*]", false));
System.out.println("categories:" + JSONPath.eval(jsonObject, "$.store.book[*].category", false));
System.out.println("categories:" + JSONPath.eval(jsonObject, "$.store.book.category", false));
}
执行结果为:
Book数目:3
books:[{"author":"Nigel Rees","price":8.95,"category":"reference","title":"Sayings of the Century"},null,{"author":"Evelyn Waugh","price":12.99,"title":"Sword of Honour"}]
categories:["reference",null,null]
categories:["reference",null,null]
切换fastjson2后,默认行为和fastjson相同,eval没有提供包含参数ignoreNullValue的接口,如果要实现相同的功能,需要使用:JSONPath.of("$.store.book[*].category", JSONPath.Feature.KeepNullValue),注意,这里如果使用$.store.book.category也会忽略值为null的value。
public void jsonTestNotIgnoreNull() {
String jsonStr = "{'store':{'book':[" +
"{'category':'reference','author':'Nigel Rees','title':'Sayings of the Century','price':8.95}," +
"null," +
"{'category':null,'author':'Evelyn Waugh','title':'Sword of Honour','price':12.99}]," +
"'bicycle':{'color':'red','price':19.95}}}\n";
JSONObject jsonObject = JSON.parseObject(jsonStr);
System.out.println("Book数目:" + JSONPath.extract(jsonStr, "$.store.book.size()", JSONPath.Feature.KeepNullValue));
System.out.println("books:" + JSONPath.extract(jsonStr, "$.store.book[*]", JSONPath.Feature.KeepNullValue));
System.out.println("categories:" + JSONPath.of("$.store.book.category", JSONPath.Feature.KeepNullValue).eval(jsonObject));
System.out.println("categories:" + JSONPath.of("$.store.book[*].category", JSONPath.Feature.KeepNullValue).eval(jsonObject));
}
执行结果为:
Book数目:3
books:[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},null,{"author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]
categories:["reference"]
categories:["reference",null,null]