早先为 Jackson 写的 Json-Path 支持
今天才发现 Jackson 其实是支持 Json-Path 的,但以前一直不知道,关键是 Jackson 的文档也没见提到。所以很久以前是自己给 Jackson 写了一个简陋的 Json-Path 支持类,这个是为测试代码用的,所以基本够用。想要更全面的功能可使用 https://github.com/jayway/JsonPath 这个项目。对于 Jackson 中如何使用 Json-Path, 我还会进一步研究下。
我写的 RichJsonNode 类是一个 Scala 版本,最早也写过一个 Java 版本,还有一个基于 GSON 的 Java 版本的。这里只贴出 Scala 版源码。支持的基本方法及语法如下:
a/b, a/b[2], a/b[1]/c, a[1]/b, $[0]
selectNode(path), selectString(path), selectInt(path), selectDouble(path), selectBollean(path), hasField(path) 和 arrayLength(path)
源码如下:
因为做成了一个用于隐式转型的类,所以在 Scala 中使用起来比较简单
如果顶级是一个数组,如 [1, 2, {"a": 3}],那么可以用
对于 Jackson 的 Json-Path 支持还正在研习当中,如果 Jackson 已足够好,我将摈弃这里的实现。 永久链接 https://yanbin.blog/jackson-json-path-support-before/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
我写的 RichJsonNode 类是一个 Scala 版本,最早也写过一个 Java 版本,还有一个基于 GSON 的 Java 版本的。这里只贴出 Scala 版源码。支持的基本方法及语法如下:
a/b, a/b[2], a/b[1]/c, a[1]/b, $[0]
selectNode(path), selectString(path), selectInt(path), selectDouble(path), selectBollean(path), hasField(path) 和 arrayLength(path)
源码如下:
1package cc.unmi<br/><br/>
2import com.fasterxml.jackson.databind.JsonNode<br/><br/>
3/**
4 * JSON PATH, Inspired by XPath, need an exact path relative to root element
5 * Can't start with "/", of course, won't support "//" fuzzy query
6 * json-path examples:
7 * <ul>
8 * <li>a/b</li>
9 * <li>a/b[2]</li>
10 * <li>a/b[1]/c</li>
11 * <li>a[1]/b</li>
12 * <li>$[0] if root element is an Array, can't use [0]/a</li>
13 * </ul>
14 */
15class RichJsonNode(json: JsonNode) {
16
17 def selectNode(jsonPath: String) = getTailElement(jsonPath)
18
19 def selectString(jsonPath: String) =
20 getTailElement(jsonPath).ensuring(t=>t.isNull||t.isTextual, "not a text node").textValue
21
22 def selectInt(jsonPath: String) =
23 getTailElement(jsonPath).ensuring(_.isInt, "not an int node").intValue()
24
25 def arrayLength(jsonPath: String) = getTailElement(jsonPath).size
26
27 def selectDouble(jsonPath: String) =
28 getTailElement(jsonPath).ensuring(_.isNumber, "not a double node").doubleValue()
29
30 def selectBoolean(jsonPath: String) =
31 getTailElement(jsonPath).ensuring(_.isBoolean, "not a boolean node").booleanValue
32
33 def isJsonNull(jsonPath: String) = getTailElement(jsonPath).isNull
34
35 def hasField(jsonPath: String): Boolean = {
36 try {
37 selectNode(jsonPath)
38 true
39 }
40 catch {
41 case _: Throwable => false
42 }
43 }
44
45 private def getTailElement(jsonPath: String): JsonNode = {
46 assume(jsonPath != null && jsonPath.trim.length > 0)
47 assume(!jsonPath.startsWith("/"), "doesn't support /a/b, or //b, path is relative")
48
49 jsonPath.split("/").foldLeft(json)((tmpJson, key) => {
50 if(key == "$"){
51 tmpJson
52 }else if (key.contains("[")) {
53 val newKey = key.substring(0, key.indexOf('['))
54 val index = """\[\d+\]""".r.findFirstIn(key).get.replaceAll("""\[|\]""","").toInt
55 if (newKey == "$") {
56 tmpJson.get(index)
57 }
58 else {
59 tmpJson.get(newKey).get(index)
60 }
61 }
62 else {
63 tmpJson.get(key)
64 }
65 });
66
67 } ensuring( _ != null)
68
69}
70
71object RichJsonNode {
72 implicit def enrich(json: JsonNode):RichJsonNode = new RichJsonNode(json)
73}因为做成了一个用于隐式转型的类,所以在 Scala 中使用起来比较简单
1import cc.unmi.RichJsonNode.enrich
2import com.fasterxml.jackson.databind.{JsonNode, ObjectMapper}
3
4object TestClient {
5 val jsonString = """{ "a": { "b": 123, "c": [1, 2, { "d": "456" } ] } }"""
6 val json = new ObjectMapper().readValue(jsonString, classOf[JsonNode])
7 System.out.println(json.selectInt("a/c[1]")) //2
8 System.out.println(json.selectString("a/b/c[2]/d") //456
9}如果顶级是一个数组,如 [1, 2, {"a": 3}],那么可以用
1json.selectInt("$[0]") //1
2json.selectint("$[2]/a") //3对于 Jackson 的 Json-Path 支持还正在研习当中,如果 Jackson 已足够好,我将摈弃这里的实现。 永久链接 https://yanbin.blog/jackson-json-path-support-before/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。