JsonPath 规范

原文地址:https://goessner.net/articles/JsonPath/

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

现在我们应该想一想,是否需要 XPath4JSON 这样的工具,它能解决哪些问题。

可以在客户端上交互式地查找数据并从 JSON 结构中提取数据,而无需编写特殊脚本。

可将客户端请求的 JSON 数据缩减为服务器上的相关部分,从而最大限度地减少服务器响应的带宽使用。

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

对于 C 系列编程语言来说,JSON 是一种自然的数据表示形式,因此特定语言很有可能拥有访问 JSON 结构的本地语法元素。

下面的 XPath 表达式:

/store/book[1]/title

会看起来像

x.store.book[0].title

或者

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

在 Javascript、Python 和 PHP 中,变量 x 包含 JSON 结构。在此我们注意到,特定语言通常已内置了基本的 XPath 功能。

  • 有关的 JSONPath 工具应...

  • 自然地基于这些语言特点。

  • 只涵盖 XPath 1.0 的基本部分。

  • 在代码大小和内存消耗方面是轻量级的。

  • 运行时高效。

|2007-08-17| e2# JSONPath 表达式

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

JSONPath 表达式可以使用点符号:

$.store.book[0].title

或括号注释

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

用于输入路径,内部或输出路径将始终转换为更通用的括号符号。

JSONPath 允许在成员名称和数组索引中使用通配符符号 *。它借用了 E4X 中的后裔运算符 "..." 和 ECMASCRIPT4 中的数组切片语法建议 [start:end:step]。

底层脚本语言的表达式(<expr>)可以用来替代明确的名称或索引,例如:

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

使用符号 "@" 表示当前对象。过滤表达式通过语法 ?(<boolean expr>) 支持,例如:

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

下面是 JSONPath 语法元素与 XPath 对应元素的完整概述和并排比较:

XPath

JSONPath

描述

/

$

根对象/元素

.

@

当前对象/元素

/

. or []

子操作符

..

n/a

父操作符

//

..

递归解析,JSONPath 从 E4X 中借鉴了这种语法。

*

*

通配符。所有对象/元素,无论其名称如何。

@

n/a

属性访问。JSON 结构没有属性。

[]

[]

下标操作符。XPath 使用它来遍历元素集合和谓词。在 Javascript 和 JSON 中,它是本地数组运算符。

|

[,]

XPath 中的联合运算符会导致节点集的组合。JSONPath 允许将备用名称或数组索引作为一个集合。

n/a

[start:end:step]

从 ES4 中借用的数组切片操作符。

[]

?()

应用过滤器(脚本)表达式。

n/a

()

脚本表达式,使用底层脚本引擎。

()

n/a

在 Xpath 中分组

XPath 提供的功能(非缩写语法的位置路径、运算符和函数)比这里列出的要多得多。此外,下标操作符在 Xpath 和 JSONPath 中的工作方式也有显著不同。

  • XPath 表达式中的方括号总是对上一个路径片段产生的节点集进行操作,索引总是以 1 开始。

  • JSONPath 中的方括号对前一个路径片段寻址的对象或数组执行操作,索引总是以 0 开始。

|2007-08-18| e3# 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 结构的所有成员。

|2007-08-22| e4# JSONPath 实现

JSONPath 在 Javascript 中实现,供客户端使用,并移植到 PHP 中供服务器使用。

使用

您只需下载以下任一文件

将其包含在你的程序中,并使用由一个函数组成的简单应用程序接口:

jsonPath(obj, expr [, args])

参数:

  • obj (object|array) 代表 JSON 结构的对象。

  • expr (string) JSONPath 表达式字符串。

  • args (object|undefined) 控制路径评估和输出的对象。目前只支持一个成员。

  • args.resultType ("VALUE"|"PATH") 会使结果变成匹配值(默认值)或规范化路径表达式。

返回值:

  • (array|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']"
]

请注意,jsonPath 的返回值是一个数组,它也是一个有效的 JSON 结构。因此,您可能需要再次将 jsonPath 应用于生成的结构,或者使用您最喜欢的数组方法对其进行排序。

|2007-08-24| e5# 问题

  • 目前 JSONPath 表达式中只允许使用单引号。

  • jsonPath 目前不会递归评估 JSONPath 位置内的脚本表达式。只有全局的 $ 和局部的 @ 符号会通过简单的正则表达式展开。

  • jsonPath 在没有匹配结果的情况下返回 false 的另一种方法是将来返回一个空数组。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号