我們先看下JSONPath的使用,這里使用的是?GitHub - json-path/JsonPath: Java JsonPath implementation,其README中已經提供了相關的介紹和使用示例,這里再簡單介紹下,我們這里直接使用其中的示例數據。
{"store": {"book": [{"category": "reference","author": "Nigel Rees","title": "Sayings of the Century","price": 8.95},{"category": "fiction","author": "Evelyn Waugh","title": "Sword of Honour","price": 12.99},{"category": "fiction","author": "Herman Melville","title": "Moby Dick","isbn": "0-553-21311-3","price": 8.99},{"category": "fiction","author": "J. R. R. Tolkien","title": "The Lord of the Rings","isbn": "0-395-19395-8","price": 22.99}],"bicycle": {"color": "red","price": 19.95}},"expensive": 10
}
-
JSONPath的表達式都是以?
$
?開始,表示根節點 -
屬性值獲取:子節點可以使用?
.<name>
?來進行表示,如:?$.store.bicycle.color
?或者?$['store']['bicycle']['color']
可以獲取其中的color值 -
獲取多個屬性值:JSONPath表達式最后一級子節點可以同時獲取多個值,如?
$['store']['bicycle']['color', 'price']
-
數組數據獲取:可以根據索引獲取指定位置元素,如:?
$.store.book[0,1]
?或者?$.store.book[:2]
?或者?$.store.book[-1]
-
可以使用通配符
*
進行匹配,如:$.store.book[*]
?或者?$.store.bicycle.*
-
深度查找可以使用
..<name>
來對屬性進行查找,而不管它的具體位置,如:$..price
-
屬性/數組過濾可以使用
[?(<expression>)]
,其中的表達式需要能解析為boolean值,如:$.store.bicycle[?(@.color=='red')]
?或者?$.store.book[?(@.price < 10)]
-
函數使用:可以使用lengh()等函數,如:
$.store.book.length()
?、$.numbers.sum()
- 相關API用法如下
final JsonPath compile = JsonPath.compile("$.store.book[0].author");
String json = "...";
final String author = compile.read(json);// 或者如果不重復使用的話,可以直接寫成一步
List<String> authors = JsonPath.read(json, "$.store.book[*].author");// 函數使用(需要注意函數能作用的數據類型,如 min(), max(), sum()等只能作用于數值數組)
String json = "{\"numbers\":[1,3,4,7,-1]}";
final Object read = JsonPath.read(json, "$.numbers.sum()"); // 輸出:14.0
- 除此之外,JsonPath還提供了一些額外的配置項,以倉庫中的 json 為例子
[{"name" : "john","gender" : "male"},{"name" : "ben"}
]
- DEFAULT_PATH_LEAF_TO_NULL
葉子節點找不到時默認為null: 正常情況下通過Path找不到數據值,JsonPath會拋出異常(使用了通配符如[*]等除外,這種找不到路徑是會返回空集合),增加此配置后在葉子結點找不到數據時會返回null 而不是異常(僅限葉子結點,中間節點不存在時仍然會拋出異常)
Configuration configuration = Configuration.builder().options(Option.DEFAULT_PATH_LEAF_TO_NULL).build();
Object data = JsonPath.using(configuration).parse(json).read("$[1]['gender']");// data == null
- ALWAYS_RETURN_LIST
不管JsonPath獲取的結果是單個值還是集合,都會包裝成集合返回
Configuration configuration = Configuration.builder().options(Option.DEFAULT_PATH_LEAF_TO_NULL, Option.ALWAYS_RETURN_LIST).build();
Object data = JsonPath.using(configuration).parse(json).read("$[*]['gender']");// data == ["male",null]// 如果默認使用的話,默認會數組對象key不存在的話會錯位上去,所以業務中如果同時有需求的話,生成 2 個 DocumentContext 去操作比較好
Object data = JsonPath.parse(json).read("$[*]['gender']");
- SUPPRESS_EXCEPTIONS
當處理發生異常時,如果配置了 ALWAYS_RETURN_LIST,則返回空集合,否則返回 null
Configuration configuration = Configuration.builder().options(Option.ALWAYS_RETURN_LIST, Option.SUPPRESS_EXCEPTIONS).build();
Object data = JsonPath.using(configuration).parse(json).read("$[0]['abc']['def']");// data = []
- REQUIRE_PROPERTIES
路徑中屬性不存在時,會拋出異常,因為本身路徑不存在就會拋出異常,所以這個配置主要體現在配置通配符的場景下,且如果同時配置了 SUPPRESS_EXCEPTIONS, 則 SUPPRESS_EXCEPTIONS 優先(不會拋出異常)
Configuration configuration = Configuration.builder().options(Option.ALWAYS_RETURN_LIST).build();
Object data = JsonPath.using(configuration).parse(json).read("$[*]['gender']");// 拋出異常
-
值替換
以上主要是讀取的操作,同時它還支持對數據進行修改,調用對應的 set 方法即可
String newJson = JsonPath.parse(json).set("$['store']['book'][0]['author']", "Paul").jsonString();