灰气球

灰气球

JSONPath 用于读取 JSON 文档的 Java DSL

105
2024-01-21

JSONPath - JSON 的 XPath

XML经常被强调的一个优点是可以使用大量工具来分析、转换和有选择地从 XML 文档中提取数据。XPath就是这些强大的工具之一。

现在是时候思考是否需要 XPath4JSON 之类的东西以及它可以解决哪些问题。

  • 可以在客户端上以交互方式从JSON结构中查找和提取数据,而无需编写特殊脚本。
  • 客户端请求的 JSON 数据可以减少到服务器上的相关部分,从而最大限度地减少服务器响应的带宽使用。

如果我们同意从手头的 JSON 结构中挑选部分的工具确实有意义,那么就会出现一些问题。它应该如何完成它的工作呢?JSONPath 表达式是什么样的?

由于 JSON 是 C 系列编程语言的数据自然表示形式,因此该特定语言很有可能具有访问 JSON 结构的本机语法元素。

以下 XPath 表达式

/store/book[1]/title

看起来像

x.store.book[0].title

或者

x['store']['book'][0]['title']

x在 Javascript、Python 和 PHP 中,带有保存 JSON 结构的变量。在这里我们观察到,特定的语言通常已经内置了基本的 XPath 功能。

有问题的 JSONPath 工具应该…

  • 自然地基于这些语言特征。
  • 仅涵盖 XPath 1.0 的基本部分。
  • 代码大小和内存消耗要轻。
  • 运行时高效。

JSONPath 表达式

JSONPath 表达式始终引用 JSON 结构,就像 XPath 表达式与 XML 文档结合使用一样。由于 JSON 结构通常是匿名的,并且不一定具有“根成员对象”,因此 JSONPath 假定$分配给外层对象的抽象名称。

JSONPath 表达式可以使用点符号

$.store.book[0].title

或括号符号

$['store']['book'][0]['title']

对于输入路径。内部或输出路径将始终转换为更通用的括号表示法。

JSONPath 允许使用通配符* 作为成员名称和数组索引。它借用了E4X的后代运算符“…”以及ECMASCRIPT 4的数组切片语法建议。[start🔚step]

底层脚本语言的表达式()可以用作显式名称或索引的替代,如

$.store.book[(@.length-1)].title

对当前对象使用符号“@”。过滤器表达式通过语法支持,?()如下所示

$.store.book[?(@.price < 10)].title

以下是 JSONPath 语法元素与其 XPath 对应项的完整概述和并排比较。

XPath JSONPath 描述
/ $ 根对象/元素
. @ 当前对象/元素
/ . or [] 子操作符
n/a 父操作员
// 递归下降。JSONPath 从 E4X 借用了此语法。
* * 通配符。所有对象/元素,无论其名称如何。
@ n/a 属性访问。JSON 结构没有属性。
[] [] 下标运算符。XPath 使用它来迭代元素集合和谓词。在 Javascript 和 JSON 中,它是原生数组运算符。
[,]
n/a [start:end:step] 数组切片运算符借用自 ES4。
[] ?() 应用过滤器(脚本)表达式。
n/a () 脚本表达式,使用底层脚本引擎。
() n/a Xpath 中的分组

XPath 提供的功能(非缩写语法、运算符和函数中的位置路径)比此处列出的要多得多。此外,下标运算符在 Xpath 和 JSONPath 中的工作方式存在显着差异。

  • XPath 表达式中的方括号始终对前一个路径片段产生的节点集进行操作。索引始终从 1 开始。
  • 使用 JSONPath 方括号可对前一个路径片段寻址的对象或数组进行操作。索引始终从 0 开始。

JSONPath 示例

让我们通过更多示例来练习 JSONPath 表达式。我们从一个简单的 JSON 结构开始,该结构是在表示书店的 XML 示例(原始XML 文件)之后构建的。

{
    "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
        }
    }
}
XPath JSONPath 结果
/store/book/author $.store.book[*].author 商店中所有书籍的作者
//author $…author 所有作者
/store/* $.store.* 商店里的所有东西,包括一些书和一辆红色自行车。
/store//price $.store…price 商店里所有东西的价格。
//book[3] $…book[2] 第三本书
//book[last()] $..book[(@.length-1)]
$…book[-1:]]
按顺序排列的最后一本书。
//book[position()<3] $..book[0,1]
$…book[:2]
前两本书
//book[isbn] $…book[?(@.isbn)] 过滤所有带有 ISBN 编号的图书
//book[price<10] $…book[?(@.price<10)] 过滤所有便宜于 10 的书籍
//* $…* XML 文档中的所有元素。JSON 结构的所有成员。

问题

  • 目前,JSONPath 表达式中只允许使用单引号。
  • 目前,JSONPath 位置内的脚本表达式不会由jsonPath. 只有全局$和局部@符号通过简单的正则表达式进行扩展。
  • 在不匹配的情况下jsonPath返回的false,另一种方法可能是将来返回一个空数组。

相关文档

Jayway JsonPath - https://github.com/json-path/JsonPath?tab=readme-ov-file
Stefan Goessner JsonPath implementation - https://goessner.net/articles/JsonPath/