galbar / jsonpath
用于查询和更新 JSON 对象的 JSONPath 实现
Requires
- php: >=5.4
Requires (Dev)
- phpunit/phpunit: ~4.0
- sami/sami: >=3.3.0
- satooshi/php-coveralls: >=1.0.1
README
这是 PHP 的 JSONPath 实现。
此实现包含规范中除 ()
操作符之外的所有元素(规范中有 $..a[(@.length-1)]
,但可以通过 $..a[-1]
实现,后者更简单)。
如果查询没有匹配项,它将返回一个空数组。
功能
此实现具有以下功能
- 正则表达式匹配键(例如
$.*[?(/^bo{2}k$/)]
或$[?(/a\wthors/)]
)。 - 正则表达式匹配值比较(例如
$.store.book[?(@.author =~ /.*Tolkien/)]
) - 对于子操作符
[]
,除非字段名称是无效的 JavaScript 变量名称,否则无需将子名称用引号括起来(例如$[store][book, bicycle]
)。 - 可以使用
.length
获取字符串的长度、获取数组的长度以及检查节点是否有子节点。 in
操作符允许在指定的列表中过滤值:$..[?(@.author in ["Nigel Rees", "Evelyn Waugh", $.store.book[3].author])]
- 面向对象实现。
- 获取、设置和 添加 操作。
- 实现了魔法方法
__get
:$obj->{'$...'}
。__set
:$obj->{'$...'} = $val
。__toString
:echo $obj
打印 JsonObject 的 JSON 表示形式。
- 不使用
eval()
。
安装
要安装 JsonPath,您需要在项目中使用 Composer。有关安装信息,请参阅文档。
composer require galbar/jsonpath
用法
在您使用的每个文件中添加以下内容
use JsonPath\JsonObject;
现在您可以创建 JsonObject 的一个实例并使用它
// $json can be a string containing json, a PHP array, a PHP object or null. // If $json is null (or not present) the JsonObject will be empty. $jsonObject = new JsonObject(); // or $jsonObject = new JsonObject($json); // get $obj->get($jsonPath); $obj->{'$.json.path'}; // set $obj->set($jsonPath, $value); $obj->{'$.json.path'} = $value; // get the json representation $obj->getJson(); $str = (string)$obj; echo $obj; // get the PHP array representation $obj->getValue(); // add values $obj->add($jsonPath, $value[, $field]); // remove values $obj->remove($jsonPath, $field);
SmartGet
在创建 JsonObject 的新实例时,您可以向构造函数传递第二个参数。这会将实例的行为设置为使用 SmartGet。
SmartGet 做的是确定给定的 JsonPath 在某个点上是否有分支,如果有,则按常规行为处理;否则,它将直接返回给定路径指向的值(而不是包含它的数组)或如果没有找到,则返回 false
。
GetJsonObjects
有时您需要访问子对象中的多个值,该子对象具有长的前缀(例如 $.a.very.long.prefix.for.[*].object
),在这种情况下,您首先获取该对象并创建它的 JsonObject,然后访问其属性。
现在,如果您想编辑对象(设置或添加值)并希望这些更改影响原始对象,则可以通过使用 JsonObject::getJsonObjects($jsonpath)
来实现。此方法与 get 的行为相同,但它将结果作为包含对源 JsonObject 中值的引用的 JsonObject 实例返回。
JsonPath 语言
此库实现了以下规范
var_name¹ = /^\.([\p{L}\p{N}\_\$][\p{L}\p{N}\_\-\$]*|\*)(.*)/u
number = ([0-9]+(\.[0-9]*) | ([0-9]*\.[0-9]+))
string = ('\''.*?'\'' | '"'.*?'"')
boolean = ('true' | 'false')
regpattern = '/'.*?'/i?x?'
null = 'null'
index = -?[0-9]+
jsonpath = '$' operator*
childpath = '@' operator*
operator = (childname | childfilter | recursive) operator*
childname = '.' (var_name | '*')
childfilter = '[' ('*' | namelist | indexlist | arrayslice | filterexpr) ']'
recursive = '..' (var_name | childfilter | '*')
namelist = var_name (',' (var_name | '\'' .*? '\'' | '"' .*? '"'))*
indexlist = index (',' index)*
arrayslice = index? ':' index? ':' index?
filterexpr = '?(' ors ' | regpattern)'
ors = ands (' ' ( 'or' | '\|\|' ) ' ' ands)*
ands = expr (' ' ( 'and' | '&&' ) ' ' expr)*
expr = ( 'not ' | '! ' )? (value | comp | in_array)
comp = value ('==' | '!=' | '<' | '>' | '<=' | '>=' | '=~') value
value = (jsonpath | childpath | number | string | boolean | regpattern | null | length)
length = (jsonpath | childpath) '.length'
in_array = value 'in' '[' value (',' value)* ']'
¹var_name
:正则表达式大致翻译为“任何有效的 JavaScript 变量名称”,包括一些怪癖,例如以数字或包含破折号(-
)开头的名称。
规范限制
- 在 value 内部的 jsonpath 不能包含
or
、and
或任何比较器。 - 在 value 中的 Jsonpaths 返回集合的第一个元素或如果没有结果则返回
false
。 - 布尔运算不能与括号一起分组。
- “与”运算符(and)的优先级高于“或”运算符(or)。这意味着
a and 1 = b or c != d
等价于(a and 1) or (c != d)
.length 操作符 可以用来
- 获取 JsonObject 中一个节点的子节点数量:
$..*[?(@.length > 3)]
- 筛选具有子节点的节点:
$..*[?(@.length)]
- 或者筛选没有子节点(叶子节点)的节点:
$..*[?(not @.length)]
- 检查字符串的长度:
$.path.to[?(@.a.string.length > 10)]
- 获取字符串的长度:
$.path.to.field.length
- 获取数组的长度:
$.path.to.array.length
- 获取数组中数组的长度:
$.path.to.array[*].array[*].length
- 获取字符串数组中字符串的长度:
$.path.to.array[*].array[*].key.length
比较运算符:
==
、!=
、<
、>
、<=
、>=
按预期工作(按类型和值进行比较)。
=~
是一个正则表达式比较运算符,将左操作数与右操作数中的模式进行匹配。左边的值必须是 字符串,右边的值是 正则表达式模式。否则返回 false
。
JsonPath 示例
考虑以下 json
{ "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95, "available": true }, { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99, "available": false }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99, "available": true }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99, "available": false } ], "bicycle": { "color": "red", "price": 19.95, "available": true } }, "authors": [ "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien" ] }
更多示例请参阅 ./tests/Galbar/JsonPath
文件夹。
测试
要运行测试,从项目根目录
php app/test.php <jsonpath> [<file to json file>]
如果没有提供 json 文件,则默认为在此文件中之前描述的 json 对象。
例如
php app/test.php "$..*[?(@.category == 'fiction' and @.price < 10 or @.color == \"red\")].price"
结果应该是
[19.95,8.99]
准备编码
文档
要生成文档,从项目根目录
php vendor/bin/sami.php update app/docgen.php