JSONPath - XPath for JSON
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']
在Javascript,Python和PHP中,带有一个保存JSON结构的变量。在这里,我们观察到,特定语言通常具有已经内置的基本XPath功能。x
有问题的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:end:step]
基础脚本语言的表达式可用作显式名称或索引的替代方法,如(<expr>)
$.store.book[(@.length-1)].title
对当前对象使用符号“@”。通过以下语法支持筛选器表达式:如?(<boolean expr>)
$.store.book[?(@.price < 10)].title
以下是 JSONPath 语法元素与其 XPath 对应元素的完整概述和并排比较。
断续器 | JSONPath | 描述 |
---|---|---|
/ |
$ |
根对象/元素 |
. |
@ |
当前对象/元素 |
/ |
. 或 []
|
子运算符 |
.. |
none | 父运算符 |
// |
.. |
递归下降。JSONPath 从 E4X 借用了这种语法。 |
* |
* |
通配符。所有对象/元素,无论其名称如何。 |
@ |
none | 属性访问。JSON 结构没有属性。 |
[] |
[] |
下标运算符。XPath 使用它来循环访问元素集合和谓词。在Javascript和JSON中,它是本机数组运算符。 |
` | ` | [,] |
none | [startstep] | 从 ES4 借用的数组片运算符。 |
[] |
?() |
应用筛选器(脚本)表达式。 |
none | () |
脚本表达式,使用基础脚本引擎。 |
() |
none | 在 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
}
}
}
断续器 | 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在Javascript中实现,用于客户端ide使用,并移植到PHP以便在服务器上使用。
用法
您需要做的就是下载其中任何一个文件
将其包含在程序中,并使用由单个函数组成的简单API。
jsonPath(obj, expr [, args])
参数:
obj (object|array)
:表示 JSON 结构的对象。
expr (string)
:表示 JSON 结构的对象。
expr (string)
:JSONPath 表达式字符串。
args (object|undefined)
:对象控制路径评估和输出。目前仅支持一个成员。
args.resultType ("VALUE"|"PATH")
:使结果为匹配值(默认值)或规范化的路径表达式。
返回值:
(array|false)
:
数组保存与输入路径表达式匹配的值或规范化路径表达式,可用于延迟求值。 如果没有匹配项。false
Javascript 示例:
var o = { /…/ }, // the ‘store’ JSON object from above res1 = jsonPath(o, “$…author”).toJSONString(), res2 = jsonPath(o, “$…author”, {resultType:“PATH”}).toJSONString();
PHP 示例:
首先,我们需要将 JSON 字符串转换为 PHP 数组。我正在使用Michal Migurski的JSON解析器来实现这一点。
require_once(‘json.php’); // JSON parser require_once(‘jsonpath.php’); // JSONPath evaluator $json = ‘{ … }’; // JSON structure from above $parser = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $o = $parser->decode($json); $match1 = jsonPath($o, “$…author”); $match2 = jsonPath($o, “$…author”, array(“resultType” => “PATH”)); $res1 = $parser->encode($match1); $res2 = $parser->encode($match2);
结果
Javascript 和 PHP 示例都生成以下 JSON 数组(作为字符串):
res1: [ “Nigel Rees”, “Evelyn Waugh”, “Herman Melville”, “J. R. R. Tolkien” ] res2: [ “$[‘store’][‘book’][0][‘author’]”, “$[‘store’][‘book’][1][‘author’]”, “$[‘store’][‘book’][2][‘author’]”, “$[‘store’][‘book’][3][‘author’]” ]
请注意,的返回值是一个数组,它也是一个有效的 JSON 结构。因此,您可能希望再次应用于生成的结构,或者像使用它一样使用您喜欢的数组方法之一。jsonPath
jsonPath
sort
问题
- 目前,JSONPath 表达式中只允许使用单引号。
- JSONPath 位置内的脚本表达式当前未由 递归计算。只有全局和局部符号由简单的正则表达式展开。
jsonPath
$
@
-
在没有匹配的情况下返回的替代方法可能是在将来返回空数组。
jsonPath
false