[](https://www.npmjs.com/package/jsonpath-plus)
[](badges/tests-badge.svg)
[](badges/coverage-badge.svg)
[](https://snyk.io/test/github/s3u/JSONPath)
<!--[](LICENSE-MIT.txt)-->
[](badges/licenses-badge.svg)
[](https://github.com/JSONPath-Plus/JSONPath/actions/workflows/node.js.yml)
<small>(另请参阅[开发依赖项的许可证](https://raw.githubusercontent.com/s3u/JSONPath/master/badges/licenses-badge-dev.svg?sanitize=true))</small>
# JSONPath Plus
分析、转换并选择性地从 JSON 文档(以及 JavaScript 对象)中提取数据。
`jsonpath-plus` 在原始规范的基础上进行了扩展,添加了一些额外的运算符,并明确了原始规范中未阐明的一些行为。
试试[浏览器演示](https://jsonpath-plus.github.io/JSONPath/demo/)或 [Runkit (Node)](https://npm.runkit.com/jsonpath-plus)。
***请注意:本项目目前未处于积极维护状态。我们可能会接受文档完善的 PR 或一些简单的更新,但不会自行进行修复或添加新功能。***
## 特性
* **兼容**原始 jsonpath 规范
* 原始规范中未提供的便捷**新增或扩展**功能:
* `^` 用于获取匹配项的**父级**
* `~` 用于获取匹配项的**属性名**(以数组形式)
* **类型选择器**,用于获取:
* 基本 JSON 类型:`@null()`、`@boolean()`、`@number()`、`@string()`、`@array()`、`@object()`
* `@integer()`
* 复合类型 `@scalar()`(在查询 JavaScript 对象时也接受 `undefined` 和非有限数字,以及所有基本的非对象/非函数类型)
* `@other()`,可与用户定义的 `otherTypeCallback` 配合使用
* 在查询非 JSON JavaScript 对象时可以使用的非 JSON 类型(`@undefined()`、`@function()`、`@nonFinite()`)
* 过滤器中的 `@path`/`@parent`/`@property`/`@parentProperty`/`@root` **简写选择器**
* **转义**
* `` ` `` 用于转义剩余序列
* `@['...']`/`?@['...']` 语法用于转义过滤器中属性名内的特殊字符
* 文档化 `$..`(**获取所有父组件**)
* **ESM** 和 **UMD** 导出格式
* 除了查询到的值之外,**还可以返回各种元信息**,包括值的路径或指针,以及父对象和父属性名(以便进行修改)。
* **用于在路径、数组和指针之间转换的工具**
* 可选择**阻止**原始规范中允许的求值,或为求值提供**沙箱**。
* 可选择在获取结果时**通过回调处理结果**。
## 基准测试
根据 [json-querying-performance-testing](https://github.com/andykais/json-querying-performance-testing),与其他 json 查询库相比,`jsonpath-plus` 在处理大型和小型数据集时始终表现良好。你可以通过[自行运行该项目](https://github.com/andykais/json-querying-performance-testing#how-to-run)并添加更多性能测试用例来验证这些发现。
## 安装
```shell
npm install jsonpath-plus
```
## 安装配置
### Node.js
```js
const {JSONPath} = require('jsonpath-plus');
const result = JSONPath({path: '...', json});
```
### 浏览器
对于浏览器使用,你可以直接包含 `dist/index-browser-umd.cjs`;无需
Browserify 魔法:
```html
<script src="node_modules/jsonpath-plus/dist/index-browser-umd.cjs"></script>
<script>
const result = JSONPath.JSONPath({path: '...', json: {}});
</script>
```
### ESM(现代浏览器)
你也可以使用 ES6 模块导入(适用于现代浏览器):
```html
<script type="module">
import {
JSONPath
} from './node_modules/jsonpath-plus/dist/index-browser-esm.js';
const result = JSONPath({path: '...', json: {}});
</script>
```
### ESM(打包工具)
或者,如果你正在打包 JavaScript(例如使用 Rollup),只需使用,
注意 [`mainFields`](https://github.com/rollup/plugins/tree/master/packages/node-resolve#mainfields)
在浏览器构建中应包含 `browser`(对于 Node,默认值会检查 `module`,应该没问题):
```js
import {JSONPath} from 'jsonpath-plus';
const result = JSONPath({path: '...', json});
```
## 用法
可用的完整签名如下:
```
const result = JSONPath([options,] path, json, callback, otherTypeCallback);
```
参数 `path`、`json`、`callback` 和 `otherTypeCallback`
也可以(连同任何其他可用属性)在 `options` 上表达。
请注意,`result` 将包含找到的所有项(可选地
包装进一个数组),而 `callback` 可用于
在发现每个项时执行某些操作,回调函数
将根据结果中要找到的独立项数量执行 0 到 N 次。
有关 `JSONPath` 可用参数的更多信息,请参阅下面的文档。
另请参阅 [API 文档](https://jsonpath-plus.github.io/JSONPath/docs/ts/)。
### 属性
可以在 options 对象或
evaluate 方法(作为第一个参数)上提供的属性包括:
- ***path***(**必需**)- JSONPath 表达式,形式为(规范化
或非规范化)字符串或数组
- ***json***(**必需**)- 要评估的 JSON 对象(无论是
null、布尔值、数字、字符串、对象还是数组类型)。
- ***autostart***(**默认值:true**)- 如果将其提供为 `false`,
可以手动调用 `evaluate` 方法。
- ***flatten***(**默认值:false**)- 返回的结果数组
是否将被展平为一维数组。
- ***resultType***(**默认值:"value"**)- 可以是大小写不敏感形式的
"value"、"path"、"pointer"、"parent" 或 "parentProperty",以分别确定
是将结果作为找到项的值返回,
作为它们的绝对路径返回,作为指向绝对路径的 [JSON Pointers](https://tools.ietf.org/html/rfc6901)
返回,作为它们的父对象返回,还是作为其父对象的
属性名返回。如果设置为 "all",所有这些类型都将返回在
一个对象上,以类型作为键名。
- ***sandbox***(**默认值:{}**)- 变量键值映射,这些变量将
可供代码评估(如过滤表达式)使用。(请注意,
当前路径和值也将可供这些
表达式使用;详情请参阅语法部分。)
- ***wrap***(**默认值:true**)- 是否将结果
包装在数组中。如果 `wrap` 设置为 `false`,且未找到结果,
将返回 `undefined`(而不是当
`wrap` 设置为 true 时的空数组)。如果 `wrap` 设置为 `false` 且找到单个
非数组结果,该结果将是唯一返回的项
(不在数组中)。然而,如果找到多个
结果,仍将返回数组。为避免歧义(在
需要区分失败结果
和空数组结果的情况下),建议将
默认值切换为 `false`。
- ***eval***(**默认值:"safe"**)- 脚本评估方法。
`safe`:在浏览器中,它将使用一个不使用 `eval` 或 `Function` 且满足内容安全策略的最小脚本引擎。在 NodeJS 中,
它没有效果,等同于 native,因为那里的脚本是安全的。
`native`:使用原生脚本能力。即在浏览器中使用不安全的 `eval` 或
`Function`,在 nodejs 中使用 `vm.Script`。`false`:禁用 JavaScript
评估表达式,并在尝试这些表达式时抛出异常。
`callback [ (code, context) => value]`:一个自定义实现,会以
`code` 和 `context` 作为参数调用,以返回评估后的值。
`class`:一个类,以 `code` 作为构造函数参数创建,并通过使用 `context`
调用 `runInNewContext` 来评估代码。
``
- ***ignoreEvalErrors***(**默认值:false**)- 忽略脚本评估期间
遇到的错误。
- ***parent***(**默认值:null**)- 在查询可能
返回根节点的情况下,这允许在结果中返回该根节点的
父节点。
- ***parentProperty***(**默认值:null**)- 在查询
可能返回根节点的情况下,这允许在结果中返回该根节点的
`parentProperty`。这可以是字符串
属性名或数字数组索引。
- ***callback***(**默认值:(none)**)- 如果提供,将在
检索到端点值时立即调用回调。提供的三个参数
将是负载的值(根据 `resultType`)、
负载的类型(无论是普通的 "value" 还是 "property"
名),以及完整的负载对象(包含所有 `resultType`)。
- ***otherTypeCallback***(**默认值:\<一个在遇到 @other() 时**
**抛出错误的函数\>**)- 在当前缺乏 JSON
Schema 支持的情况下,可以通过在查询末尾添加运算符 `@other()` 来确定内置类型之外的类型。如果遇到这样的
路径,将使用该项的值、其路径、其父对象及其父对象的属性名
调用 `otherTypeCallback`,
它应返回一个布尔值,指示所提供的值
是否属于 "other" 类型(或者它可以处理转换并
返回 false)。
- ***customTypes***(**默认值:{}**)- 类型名到函数的键值映射。
这允许创建可在查询中使用的自定义类型运算符
(例如 `@myType()`)。该函数将使用该项的值、
其路径、其父对象及其父对象的属性名调用。它应返回一个
布尔值,指示所提供的值是否匹配自定义类型。也可以
设置为:
1. 导入 `jsonpath-plus/src/structuredCloningTypes.js` 的值,它预定义了以下类型:
@NaN(), @BigIntObject(), @Date(), @Set(), @Map(), @RegExp(),
@Blob(optionalMimeType), @File(optionalMimeType), @Boolean(), @Number(),
@String(), @Infinity(), @negativeInfinity(), @negativeZero(),
@DOMException(), @Error(), @EvalError(), @RangeError(), @ReferenceError(),
@SyntaxError(), @TypeError(), @URIError(), @AggregateError(),
@QuotaExceededError(), @WebTransportError(), @FileList, @ArrayBuffer(),
@DataView(), @ImageData(), @ImageBitmap(), @Int8Array(), @Uint8Array(),
@Uint8ClampedArray(), @Int16Array(), @Uint16Array(), @Int32Array(),
@Uint32Array(), @Float32Array(), @Float64Array(), @BigInt64Array(),
@BigUint64Array(), @Float16Array, @DOMMatrix(), @DOMMatrixReadOnly(),
@DOMPoint(), @DOMPointReadOnly(), @DOMRect, @DOMRectReadOnly(),
@DOMQuad(), @CryptoKey(), @AudioData(), @EncodedAudioChunk(),
@EncodedVideoChunk(), @VideoFrame(), @CropTarget,
@FileSystemDirectoryHandle(), @FileSystemFileHandle(),
@GPUCompilationInfo(), @GPUCompilationMessage(),
@GPUPipelineError(), @RTCCertificate(), @RTCEncodedAudioFrame(),
@RTCEncodedVideoFrame()
2. 导入 `jsonpath-plus/src/javascriptTypes.js` 的值,它预定义了以下类型:
@Generator(), @AsyncGenerator(), @GeneratorFunction(),
@AsyncGeneratorFunction(), @Iterable(), @AsyncIterable(), @Iterator()
### 实例方法
- ***evaluate(path, json, callback, otherTypeCallback)*** 或
***evaluate({path: \<path\>, json: \<json object\>, callback:***
***\<callback function\>, otherTypeCallback:***
***\<otherTypeCallback function\>})*** - 仅当
`autostart` 属性设置为 `false` 时,此方法才是
必要的。它可用于使用相同配置进行重复评估。
除了列出的属性外,后一种方法模式可以
接受任何其他允许的实例属性(除了
`autostart`,它在这里没有相关性)。
### 类属性和方法
- ***JSONPath.clearCache()*** - 清除内部缓存的已解析路径和
已编译脚本。缓存内容不会暴露;在
需要使缓存失效时调用此方法。
- ***JSONPath.toPathArray(pathAsString)*** - 接受规范化或
非规范化路径字符串并转换为数组:例如,
`['$', 'aProperty', 'anotherProperty']`。
- ***JSONPath.toPathString(pathAsArray)*** - 接受路径数组并
转换为规范化路径字符串。该字符串将采用如下形式:
`$['aProperty']['anotherProperty][0]`。JSONPath 终端
构造 `~` 和 `^` 以及类型运算符如 `@string()` 将被
静默剥离。
- ***JSONPath.toPointer(pathAsArray)*** - 接受路径数组并
转换为 [JSON Pointer](https://tools.ietf.org/html/rfc6901)。
该字符串将采用如下形式:`/aProperty/anotherProperty/0`
(其中任何 `~` 和 `/` 内部字符都按照 JSON
Pointer 规范进行转义)。JSONPath 终端构造 `~` 和 `^` 以及
类型运算符如 `@string()` 将被静默剥离。
## 通过示例了解语法
给定以下 JSON,取自 <http://goessner.net/articles/JsonPath/>:
```json
{
"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
}
}
}
```
以及以下 XML 表示:
```xml
<store>
<book>
<category>reference</category>
<author>Nigel Rees</author>
<title>Sayings of the Century</title>
<price>8.95</price>
</book>
<book>
<category>fiction</category>
<author>Evelyn Waugh</author>
<title>Sword of Honour</title>
<price>12.99</price>
</book>
<book>
<category>fiction</category>
<author>Herman Melville</author>
<title>Moby Dick</title>
<isbn>0-553-21311-3</isbn>
<price>8.99</price>
</book>
<book>
<category>fiction</category>
<author>J. R. R. Tolkien</author>
<title>The Lord of the Rings</title>
<isbn>0-395-19395-8</isbn>
<price>22.99</price>
</book>
<bicycle>
<color>red</color>
<price>19.95</price>
</bicycle>
</store>
```
请注意,下面的 XPath 示例不区分检索元素与其文本内容(除非在比较或为避免歧义时有用)。注意:要测试这些 XPath 示例(包括 2.0 的示例),[这个演示](http://videlibri.sourceforge.net/cgi-bin/xidelcgi)可能会有帮助(设置为 `xml` 或 `xml-strict`)。
| XPath | JSONPath | 结果 | 备注 |
|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `/store/book/author` | `$.store.book[*].author` | 商店中所有书籍的作者 | 也可以不使用 `$.` 表示为 `store.book[*].author`(尽管原始规范中并未包含此写法);但请注意,某些字符字面量(`$` 和 `@`)需要转义 |
| `//author` | `$..author` | 所有作者 | |
| `/store/*` | `$.store.*` | 商店中的所有内容,即其书籍(一个书籍数组)和一辆红色自行车(一个自行车对象)。 | |
| `/store//price` | `$.store..price` | 商店中所有物品的价格。 | |
| `//book[3]` | `$..book[2]` | 第三本书(书籍对象) | |
| `//book[last()]` | `$..book[(@.length-1)]` <br> `$..book[-1:]` | 最后一本书。 | 要访问带有特殊字符的属性,请使用 `[(@['...'])]` 作为过滤器(此特定功能不在原始规范中) |
| `//book[position()<3]` | `$..book[0,1]` <br> `$..book[:2]` | 前两本书 | |
| `//book/*[self::category\|self::author]` 或 XPath 2.0 中的 `//book/(category,author)` | `$..book[0][category,author]` | 所有书籍的类别和作者 | |
| `//book[isbn]` | `$..book[?(@.isbn)]` | 筛选所有带有 ISBN 编号的书籍 | 要访问带有特殊字符的属性,请使用 `[?@['...']]` 作为过滤器(此特定功能不在原始规范中) |
| `//book[price<10]` | `$..book[?(@.price<10)]` | 筛选所有价格低于 10 的书籍 | |
| `//*[name() = 'price' and . != 8.95]` | `$..*[?(@property === 'price' && @ !== 8.95)]` | 获取属性为 price 且不等于 8.95 的对象的所有属性值 | 使用裸 `@` 允许按属性值筛选对象(不一定在数组内),你可以在表达式后添加 `^` 来获取拥有被筛选属性的对象 |
| `/` | `$` | JSON 对象的根(即整个对象本身) | 要获取字面量 `$`(单独或路径中的任何位置),必须使用反引号转义 |
| `//*/*\|//*/*/text()` | `$..*` | XML 文档中根下的所有元素(和文本)。JSON 结构中根下的所有成员。 | |
| `//*` | `$..` | XML 文档中的所有元素。JSON 结构的所有父组件,包括根。 | 此行为未在原始规范中直接指定 |
| `//*[price>19]/..` | `$..[?(@.price>19)]^` | 价格大于 19 的特定项的父级(即作为自行车父级的 store 值,以及作为单本书父级的 book 数组) | 父级(脱字符)不在原始规范中 |
| `/store/*/name()`(XPath 2.0 中) | `$.store.*~` | store 子对象的属性名("book" 和 "bicycle")。与通配符属性一起使用时很有用。 | 属性名(波浪号)不在原始规范中 |
---
[Read more](https://github.com/jsonpath-plus/jsonpath)