JsonPath使用(Java)
Java有一些类似于jq的语法库和工具。其中一个叫做JsonPath,它允许使用类似于jq的语法来查询和操作JSON数据。可以使用JsonPath来提取特定的JSON字段、过滤数据、执行计算等操作。另外,还有一些其他的Java库和框架也提供了类似的功能,比如FastJson,Gson和Jackson。这些库可以在Java中更方便地处理和操作JSON数据。
这里只写常用的两种JsonPath和FastJson的使用示例(相对而言,fastjson功能更为强大,语法更丰富)。
JsonPath
用于读取 JSON 文档的 Java DSL。
语法
JSONPATH | 描述 |
---|---|
$ |
根对象,例如 $.name. |
@ |
处理当前节点的表达式.例如 $.users[?(@.age > 26)] |
* |
通配符,对象的所有属性,例如$.leader.* |
.. |
deepScan 属性访问,例如 $..name |
.<name> |
调用当前节点的子项,例如 $.name |
['<name>' (, '<name>')] |
多个属性访问。例如$['id','name'] |
[<number> (, <number>)] |
数组多个元素访问,其中num是数字,可以是负数,返回数组中的多个元素。例如$[0,3,-2,5] |
[start:end] |
数组范围访问,其中 start 和 end 是开始小表和结束下标,可以是负数,返回数组中的多个元素。例如 $[0:5] |
[?(<expression>)] |
过滤表达式,必须为Boolean类型 |
代码示例
public class TestCase {
@Test
public void json() {
String json = "{\"name\": \"John\", \"age\": 30}";
ReadContext ctx = JsonPath.parse(json);
String name = ctx.read("$.name");
int age = ctx.read( "$.age");
System.out.println("name: " + name + " ; age: " + age);
json = "[\"jack\",\"tom\"]";
ctx = JsonPath.parse(json);
System.out.println(ctx.jsonString()+ " - "+ ctx.read("$.[0]"));
}
@Test
public void array() {
String json = "{\"users\": [{\"name\": \"John\", \"age\": 30}, {\"name\": \"Jane\", \"age\": 25}]}";
ReadContext ctx = JsonPath.parse(json);
// 使用JsonPath表达式查询数组数据:
// 使用JsonPath表达式$.users[*].name和$.users[*].age分别从JSON数组中提取了所有用户的姓名和年龄。
// 使用了通配符[*]来表示所有数组元素
List<String> names = ctx.read( "$.users[*].name");
System.out.println(names); // ["John","Jane"]
String name = ctx.read( "$.users[0].name");
System.out.println(name); // John
// 使用JsonPath表达式$.users[0] 来查询数组第一个元素
Map<String, Object> user = ctx.read( "$.users[0]");
System.out.println(user); // {name=John, age=30}
// 迭代数组:
// 可以使用JsonPath表达式迭代JSON数组并执行其他操作。
// 例如,以下示例使用JsonPath表达式迭代JSON数组并计算所有用户的平均年龄:
List<Integer> ages = ctx.read( "$.users[*].age");
double averageAge = ages.stream().mapToInt(Integer::intValue).average().orElse(0.0);
System.out.println(averageAge); // 27.5
}
@Test
public void arrayAndCompare() {
String json = "{\n" +
" \"users\": [\n" +
" {\n" +
" \"name\": \"John\",\n" +
" \"age\": 30\n" +
" },\n" +
" {\n" +
" \"name\": \"Jane\",\n" +
" \"age\": 25\n" +
" },\n" +
" {\n" +
" \"name\": \"Bob\",\n" +
" \"age\": 40\n" +
" }\n" +
" ]\n" +
"}";
ReadContext ctx = JsonPath.parse(json);
// 获取所有年龄大于30岁的用户的姓名。使用JsonPath表达式的条件语句来实现
// JsonPath表达式$.users[?(@.age > 30)].name来获取所有年龄大于30岁的用户的姓名。
// 请注意,条件语句[?(@.age > 30)]来判断每个用户的年龄是否大于30岁,并只获取符合条件的用户的姓名。
// 可以使用其他条件语句来实现更复杂的逻辑,例如逻辑运算符(如AND和OR)和比较运算符(如等于和不等于)。
List<String> names = ctx.read( "$.users[?(@.age > 30)].name");
System.out.println(names); // ["Bob"]
// JsonPath表达式不支持使用表达式后提取数组下标,如:$.users[?(@.age > 30)][0]
// https://github.com/json-path/JsonPath/issues/272, 可以使用 fastjson 实现,fastjson支持该语法
names = ctx.read( "$.users[?(@.age >= 30)][0]"); // 这个表达式现在不支持
System.out.println(names); // []
// 获取所有年龄大于30岁的用户
List<String> users = ctx.read( "$.users[?(@.age > 30)]");
System.out.println(users); // [{"name":"Bob","age":40}]
// 获取第一个用户
Map<String, Object> user = ctx.read( "$.users[0]");
System.out.println(user); // {name=John, age=30}
// 获取所有年龄大于30岁的用户中的第一个姓名。由于JsonPath不支持表达式后直接使用数组下标,只能使用Java代码处理
// 使用JsonPath表达式$.users[?(@.age > 30)].name来获取所有年龄大于30岁的用户的姓名,并使用Java代码来处理结果
names = ctx.read("$.users[?(@.age > 30)].name");
String firstName = names.isEmpty() ? null : names.get(0);
System.out.println(firstName); // Bob
// 获取所有年龄大于50岁的用户的姓名,并在数组为空时返回默认值"jack",否则返回姓名数组中的第一个值
names = ctx.read( "$.users[?(@.age > 50)].name");
firstName = names.isEmpty() ? "jack" : names.get(0);
System.out.println(names); // []
System.out.println(firstName); // jack
}
}
FastJson
fastjson 1.2.0之后的版本支持JSONPath。可以在java框架中当作对象查询语言(OQL)来使用。
语法
JSONPATH | 描述 |
$ | 根对象,例如 $.name |
[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'] |
语法示例
JSONPath | 语义 |
$ | 根对象 |
$[-1] | 最后元素 |
$[:-2] | 第 1 个至倒数第 2 个 |
$[1:] | 第 2 个之后所有元素 |
$[1,2,3] | 集合中 1,2,3 个元素 |
代码示例
public class TestCase {
private String json = "{\"users\": [{\"name\": \"John\", \"age\": 30}, {\"name\": \"Jane\", \"age\": 25}]}";
@Test
public void json() {
JSONObject jsonObject = JSON.parseObject(json);
JSONArray users = (JSONArray) JSONPath.eval(jsonObject, "$.users");
System.out.println(users); // [{"name":"John","age":30},{"name":"Jane","age":25}]
JSONArray names = (JSONArray) JSONPath.eval(jsonObject, "$.users.name");
System.out.println(names); // ["John","Jane"]
String name = (String) JSONPath.eval(jsonObject, "$.users[1].name");
System.out.println(name); // Jane
}
/**
* use && and || to combine multiple predicates
* [?(@.price < 10 && @.category == 'fiction')] , [?(@.category == 'reference' || @.price > 10)].
*
* use ! to negate a predicate
* [?(!(@.price < 10 && @.category == 'fiction'))].
*/
@Test
public void array() {
JSONObject jsonObject = JSON.parseObject(json);
JSONArray users = (JSONArray) JSONPath.eval(jsonObject, "$.users[?(@.age > 26)]");
System.out.println("年龄大于26的 user:" + users); // [{"name":"John","age":30}]
users = (JSONArray) JSONPath.eval(jsonObject, "$.users[?(@.age > 20 && @.age < 30)]");
System.out.println("年龄大于20并且小于30的 user:" + users); // [{"name":"Jane","age":25}]
users = (JSONArray) JSONPath.eval(jsonObject, "$.users[?(@.age > 20 && @.name like 'Jo%')]");
System.out.println("年龄大于20并且name以'Jo'开头的 user:" + users); // [{"name":"John","age":30}]
JSONObject user = (JSONObject) JSONPath.eval(jsonObject, "$.users[?(@.age > 20)][0]");
System.out.println("年龄大于20的第一个 user:" + user); // {"name":"John","age":30}
JSONArray names = (JSONArray) JSONPath.eval(jsonObject, "$.users[?(@.age > 26)].name");
System.out.println("年龄大于26的 name:" + names); // ["John"]
names = (JSONArray) JSONPath.eval(jsonObject, "$.users[?(@.age >= 20)].name");
System.out.println("年龄大于20的 name:" + names); // ["John","Jane"]
String name = (String) JSONPath.eval(jsonObject, "$.users[?(@.age >= 20)][1].name");
System.out.println("年龄大于20的第一个name:" + name); // Jane
}
}
标签:Java,users,age,30,JsonPath,使用,println,name
From: https://www.cnblogs.com/tomoncle/p/17772263.html