JsonPath 基本使用
一、JSONPath 介绍
XML 格式的优点之一是可以使用很多工具来分析、转换和有选择地从 XML 文档中提取数据。 XPath 就是这些强大的工具之一。而对于 JSON 文档,也有类似的 JSONPath 规范(可以说是事实上的业内标准)。
通俗易懂地讲,就是可以通过形如 $.tool.jsonpath.creator
的「路径」来表示 JSON 文档内部嵌套的任意属性与值。
Jayway JsonPath 就是 JSONPath 规范的一个广为使用的 Java 实现。本文就简要介绍该库的基本使用。
此外,alibaba 的 fastjson 也支持 JSONPath。
二、使用示例
以如下的 JSON 文本举例:
{
"tool": {
"jsonpath": {
"creator": {
"name": "Jayway Inc.",
"location": [
"Malmo",
"San Francisco",
"Helsingborg"
]
}
}
},
"book": [
{
"title": "Beginning JSON",
"price": 49.99
},
{
"title": "JSON at Work",
"price": 29.99
}
]
}
2.1 基本语法:
$
表示根节点,@
表示当前节点,*
表示通配符;- 使用
.
或者[]
分隔节点及其相邻节点。例如,用$.tool.jsonpath.creator.location[2]
或者$['tool']['jsonpath']['creator']['location'][2]
都可以获取到上面 JSON 文本里的"Helsingborg"
。
2.2 主要 API:
<T> T JsonPath.read(String jsonString, String jsonPath, Predicate... filters);
<T> T JsonPath.parse(String jsonString).read(String jsonPath, Predicate... filters);
话不多说,直接上代码:
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.spi.json.GsonJsonProvider;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.mapper.GsonMappingProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
public class JsonPathTest {
/**
* <pre> json:
* {
* "tool": {
* "jsonpath": {
* "creator": {
* "name": "Jayway Inc.",
* "location": [
* "Malmo",
* "San Francisco",
* "Helsingborg"
* ]
* }
* }
* },
* "book": [
* {
* "title": "Beginning JSON",
* "price": 49.99
* },
* {
* "title": "JSON at Work",
* "price": 29.99
* }
* ]
* }
* </pre>
*/
private static final String json = "{\"tool\":{\"jsonpath\":{\"creator\":{\"name\":\"Jayway Inc.\",\"location\":[\"Malmo\",\"San Francisco\",\"Helsingborg\"]}}},\"book\":[{\"title\":\"Beginning JSON\",\"price\":49.99},{\"title\":\"JSON at Work\",\"price\":29.99}]}";
public static void main(String[] args) throws Exception {
String path1 = "$.tool.jsonpath.creator.location[1]";
String path2 = "$['tool']['jsonpath']['creator']['location'][*]";
String path3 = "$.book..title";
String path4 = "$.book[1]";
DocumentContext jsonContext = JsonPath.parse(json);
// 读出来的对象是 1.Java原生类型 或者 2.JsonPath 库的类型
Object o1 = JsonPath.read(json, path1); // class java.lang.String
Object o2 = jsonContext.read(path2); // class net.minidev.json.JSONArray
// 可以直接用正确的类型接收返回值
net.minidev.json.JSONArray o3 = jsonContext.read(path3);
java.util.LinkedHashMap o4 = jsonContext.read(path4); // 很奇怪 o4 的类型是 Map 而不是 net.minidev.json.JSONObject
// 如果想使用 Gson 的 JSON 动态类型,需要
Configuration gsonConf = Configuration.builder()
.jsonProvider(new GsonJsonProvider())
.mappingProvider(new GsonMappingProvider())
.build();
DocumentContext gsonContext = JsonPath.using(gsonConf).parse(json);
Object g1 = gsonContext.read(path1); // class com.google.gson.JsonPrimitive
Object g2 = gsonContext.read(path2); // class com.google.gson.JsonObject
com.google.gson.JsonArray g3 = gsonContext.read(path3);
com.google.gson.JsonObject g4 = gsonContext.read(path4);
// 如果想使用 Jackson 的 JSON 动态类型,需要
Configuration jacksonConf = Configuration.builder()
.jsonProvider(new JacksonJsonNodeJsonProvider()) // 注意:不是 JacksonJsonProvider
.mappingProvider(new JacksonMappingProvider())
.build();
DocumentContext jacksonContext = JsonPath.using(jacksonConf).parse(json);
Object k1 = jacksonContext.read(path1); // class com.fasterxml.jackson.databind.node.TextNode
Object k2 = jacksonContext.read(path2); // class com.fasterxml.jackson.databind.node.ObjectNode
com.fasterxml.jackson.databind.node.ArrayNode k3 = jacksonContext.read(path3);
com.fasterxml.jackson.databind.node.ObjectNodek4 = jacksonContext.read(path4);
}
}
注意几个地方:
read()
方法返回值使用了泛型,所以可以用任意类型来接收返回值。但是如果使用了错误的类型,则会抛出java.lang.ClassCastException
。- 如果想使用
Gson
或者Jackson
的 JSON 动态类型,需要配置Configuration
后再解析。至于这两个 JSON 库的基本介绍与使用在我的前一篇博文中有讲。
最后,更多语法以及高级用法(如Predicates
和Options
等)可以自行去查阅 JSONPath 规范 和 Jayway JsonPath 的文档。