remorhaz / php-json-path
PHP 中的 JSONPath 实现
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0
- ext-intl: *
- ext-json: *
- nikic/php-parser: ^4.12 || ^5
- remorhaz/php-json-data: ^0.7
- remorhaz/php-unilex: ^0.5.3
Requires (Dev)
- bamarni/composer-bin-plugin: ^1.8
- phpunit/phpunit: ^10.1 || ^11
README
JSONPath 是一种简单的 JSON 文档查询语言,受 XPath (XML 的查询语言) 启发,最初由 Stefan Goessner 设计。
特性
- 接受编码的 JSON 字符串以及解码的 PHP 数据作为输入,同时支持两种表示方式在输出。
- 使用 JSONPath 查询选择、删除或替换 JSON 文档的部分。
- 识别明确的/不明确的 JSONPath 查询而不执行它们。
- 将不明确的 JSONPath 查询转换为针对给定 JSON 文档的明确查询集合。
要求
- PHP 8
- JSON 扩展 (ext-json) - 由 remorhaz/php-json-data 使用,用于访问 JSON 文档。
- 国际化函数 (ext-intl)
- 分词器扩展 (ext-tokenizer) - 由 nikic/php-parser 使用,用于代码生成。
安装
您可以使用 Composer 安装此包
composer require remorhaz/php-json-path
用法
访问 JSON 文档
您可以使用相应的 节点值工厂 从编码的 JSON 字符串或解码的 JSON 数据创建可访问的 JSON 文档。
use Remorhaz\JSON\Data\Value\EncodedJson; use Remorhaz\JSON\Data\Value\DecodedJson; // Creating document from JSON-encoded string: $encodedValueFactory = EncodedJson\NodeValueFactory::create(); $encodedJson = '{"a":1}'; $document1 = $encodedValueFactory->createValue($encodedJson); // Creating document from decoded JSON data: $decodedValueFactory = DecodedJson\NodeValueFactory::create(); $decodedJson = (object) ['a' => 1]; $document2 = $decodedValueFactory->createValue($decodedJson);
创建查询
您应该使用 查询工厂 从 JSONPath 表达式创建查询
use Remorhaz\JSON\Path\Query\QueryFactory; $queryFactory = QueryFactory::create(); // Creating query that selects all 'a' properties from any document: $query = $queryFactory->createQuery('$..a');
明确的 查询是定义文档中确切一个路径的查询。如果查询包含任何过滤器、通配符或深层子节点扫描,则被视为 不明确的。
可访问的 查询是返回文档未处理部分的查询。如果查询返回聚合函数结果,则被视为 不可访问的。
处理查询
您应该使用 查询处理器 的实例在给定的 JSON 文档上执行查询
use Remorhaz\JSON\Path\Processor\Processor; $processor = Processor::create();
选择 JSON 文档的一部分
使用 JSONPath 查询选择 JSON 文档的部分有两种方法
- 您可以使用
::select()
方法获取所有匹配的部分,这将与 明确的 和 不明确的 查询一起工作。如果文档的任何部分都不匹配您的查询,您将得到一个空数组。 - 您可以使用
::selectOne()
方法获取恰好一个匹配的部分。请注意,这仅适用于 明确的 查询。如果您的查询是不明确的,您将得到一个异常。
use Remorhaz\JSON\Data\Value\EncodedJson; use Remorhaz\JSON\Path\Processor\Processor; use Remorhaz\JSON\Path\Query\QueryFactory; $processor = Processor::create() $queryFactory = QueryFactory::create(); $encodedValueFactory = EncodedJson\NodeValueFactory::create(); $document = $encodedValueFactory->createValue('{"a":{"a":1,"b":2}'); // Selecting all 'a' properties (indefinite query, values exist): $query1 = $queryFactory->createQuery('$..a'); $result1 = $processor->select($query1, $document); var_dump($result1->select()); // array: ['{"a":1,"b":2}', '1'] // Selecting single 'b' property nested in 'a' property (definite query, value exists): $query2 = $queryFactory->createQuery('$.a.b'); $result2 = $processor->selectOne($query2, $document); var_dump($result2->exists()); // boolean: true var_dump($result2->decode()); // integer: 2 // Selecting single 'b' property (definite query, value doesn't exist): $query3 = $queryFactory->createQuery('$.b'); $result3 = $processor->selectOne($query3, $document); var_dump($result3->exists()); // boolean: false var_dump($result3->decode()); // throws exception
请注意,您可以将选择的结果编码为 JSON 字符串或解码为原始 PHP 数据。在访问 ::selectOne()
的结果之前,您可以使用 ::exists()
方法检查其存在性,以避免异常。
删除 JSON 文档的一部分
要删除 JSON 文档的一部分,请使用 ::delete()
方法。它仅适用于 可访问的 查询。如果您的查询是不可访问的,您将得到一个异常。如果没有文档部分匹配查询,您将得到未更改的文档。特殊情况是删除文档的根 - 在这种情况下,您将得到不存在的结果。
use Remorhaz\JSON\Data\Value\EncodedJson; use Remorhaz\JSON\Path\Processor\Processor; use Remorhaz\JSON\Path\Query\QueryFactory; $processor = Processor::create() $queryFactory = QueryFactory::create(); $encodedValueFactory = EncodedJson\NodeValueFactory::create(); $document = $encodedValueFactory->createValue('{"a":{"a":1,"b":2}'); // Deleting all 'b' properties (value exists): $query1 = $queryFactory->createQuery('$..b'); $result1 = $processor->delete($query1, $document); var_dump($result1->exists()); // boolean: true var_dump($result1->encode()); // '{"a":{"a":1}}' // Deleting all 'c' properties (value doesn't exist): $query2 = $queryFactory->createQuery('$..c'); $result2 = $processor->delete($query2, $document); var_dump($result1->exists()); // boolean: true var_dump($result1->encode()); // '{"a":{"a":1,"b":2}}' // Deleting root of the document: $query3 = $queryFactory->createValue('$'); $result3 = $processor->delete($query3, $document); var_dump($result3->exists()); // boolean: false var_dump($result3->encode()); // throws exception
使用另一个 JSON 文档替换 JSON 文档的一部分
要用另一个JSON文档替换JSON文档的某部分,请使用::replace()
方法。此方法仅适用于可寻址查询。如果您的查询不可寻址,您将收到异常。如果没有文档部分与查询匹配,您将获得未更改的文档。如果查询匹配文档的嵌套部分,您也将收到异常。
use Remorhaz\JSON\Data\Value\EncodedJson; use Remorhaz\JSON\Path\Processor\Processor; use Remorhaz\JSON\Path\Query\QueryFactory; $processor = Processor::create() $queryFactory = QueryFactory::create(); $encodedValueFactory = EncodedJson\NodeValueFactory::create(); $document1 = $encodedValueFactory->createValue('{"a":{"a":1,"b":2}'); $document2 = $encodedValueFactory->createValue('{"c":3}'); // Replacing 'a' property (value exists): $query1 = $queryFactory->createQuery('$.a'); $result1 = $processor->replace($query1, $document1, $document2); var_dump($result1->encode()); // string: '{"a":{"c":3}}' // Replacing all 'c' properties (value doesn't exist) $query2 = $queryFactory->createQuery('$..c'); $result2 = $processor->replace($query2, $document1, $document2); var_dump($result2->encode()); // string: '{"a":{"a":1,"b":2}' // Replacing all 'a' properties (values are nested): $query3 = $queryFactory->createQuery('$..a'); $result3 = $processor->replace($query3, $document1, $document2); // throws exception
语法
所有JSONPath查询都以抽象的$
符号开头,该符号表示外部级别对象。内部结构可以通过子运算符和过滤器进行匹配
子运算符
选择结构子项有两种表示法:点表示法和括号表示法。
点表示法允许选择确切的一个属性或所有子项(使用通配符)。双点表示法递归地遍历JSON结构。
括号表示法允许选择一组属性/元素
聚合函数
可以将聚合函数附加到查询中的任何路径,并将返回计算值。
聚合函数集合和这一想法取自Java实现。
过滤器表达式
当过滤器应用于节点集时,它仅保留那些表达式求值为真的节点。
过滤器上下文
表达式@
指向应用过滤器时的值。
运算符
比较运算符可以用于将值与另一个值或文字进行比较。支持的运算符有:==
、!=
、>
、>=
、<
和<=
。括号可用于分组,并且还支持逻辑运算符&&
、||
和!
。可以使用=~
运算符进行正则表达式匹配。
原始定义
Goessner通过提供一组对JSON样本的示例查询来描述JSONPath语法。以下是他的原始数据样本
{ "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 } } }
以下是他的原始示例查询及其结果描述