clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use Utilities\ArraySlice;
use JsonPath\Language;
class ArrayInterval
{
public static function evaluate(&$partial, $numbers) {
$begin = null;
$step = null;
$end = null;
// $numbers has the different numbers of the interval
// depending on if there are 2 (begin:end) or 3 (begin:end:step)
// numbers $begin, $step, $end are reassigned
if (count($numbers) === 3) {
$step = ($numbers[2] !== '' ? intval($numbers[2]) : $step);
}
$end = ($numbers[1] !== '' ? intval($numbers[1]) : $end);
$begin = ($numbers[0] !== '' ? intval($numbers[0]) : $begin);
$slice = ArraySlice::slice($partial, $begin, $end, $step, true);
$result = array();
foreach ($slice as $i => $x) {
if ($x !== null) {
$result[] = &$slice[$i];
}
}
return $result;
}
}

View File

@@ -0,0 +1,65 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class BooleanExpression
{
public static function evaluate(&$root, &$partial, $expression)
{
$ands = preg_split(Language\Regex::BINOP_OR, $expression);
foreach ($ands as $subexpr) {
if (BooleanExpression::booleanExpressionAnds($root, $partial, $subexpr)) {
return true;
}
}
return false;
}
private static function booleanExpressionAnds(&$root, &$partial, $expression)
{
$values = preg_split(Language\Regex::BINOP_AND, $expression);
$match = array();
foreach ($values as $subexpr) {
$not = false;
if (preg_match(Language\Regex::OP_NOT, $subexpr, $match)) {
$subexpr = $match[2];
$not = true;
}
$result = false;
if (preg_match(Language\Regex::BINOP_COMP, $subexpr, $match)) {
$result = Comparison::evaluate($root, $partial, $match[1], $match[2], $match[3]);
}
else {
$result = Value::evaluate($root, $partial, $subexpr);
}
if ($not) {
if ($result !== false) {
return false;
}
} else {
if ($result === false) {
return false;
}
}
}
return true;
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class ChildNameList
{
public static function evaluate(&$partial, $names, $createInexistent = false) {
$names = array_filter(
$names,
function($x) use ($createInexistent, $partial) {
return $createInexistent || array_key_exists($x, $partial);
}
);
$result = array();
foreach ($names as $name) {
if (!array_key_exists($name, $partial)) {
$partial[$name] = array();
}
$result[] = &$partial[$name];
}
return $result;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class Comparison
{
public static function evaluate(&$root, &$partial, $leftExpr, $comparator, $rightExpr)
{
$left = Value::evaluate($root, $partial, trim($leftExpr));
$right = Value::evaluate($root, $partial, trim($rightExpr));
if ($comparator === Language\Token::COMP_EQ) {
return $left === $right;
} else if ($comparator === Language\Token::COMP_NEQ) {
return $left !== $right;
} else if ($comparator === Language\Token::COMP_LT) {
return $left < $right;
} else if ($comparator === Language\Token::COMP_GT) {
return $left > $right;
} else if ($comparator === Language\Token::COMP_LTE) {
return $left <= $right;
} else if ($comparator === Language\Token::COMP_GTE) {
return $left >= $right;
} else { // $comparator === Language\Token::COMP_RE_MATCH
if (is_string($right) && is_string($left)) {
return (bool) preg_match($right, $left);
}
return false;
}
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
class IndexList
{
public static function evaluate(&$partial, $indexes, $createInexistent = false) {
$indexes = array_map(
function($i) use ($partial) {
if ($i < 0) {
$n = count($partial);
$i = $i % $n;
if ($i < 0) {
$i += $n;
}
}
return $i;
},
$indexes
);
$indexes = array_filter(
$indexes,
function($x) use ($createInexistent, $partial) {
return $createInexistent || array_key_exists($x, $partial);
}
);
$result = array();
foreach ($indexes as $i) {
if (!array_key_exists($i, $partial)) {
$partial[$i] = array();
}
$result[] = &$partial[$i];
}
return $result;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Expression;
use JsonPath\Language;
use JsonPath\Operation;
class Value
{
public static function evaluate(&$root, &$partial, $expression)
{
if ($expression === Language\Token::VAL_NULL) {
return null;
} else if ($expression === Language\Token::VAL_TRUE) {
return true;
} else if ($expression === Language\Token::VAL_FALSE) {
return false;
} else if (is_numeric($expression)) {
return floatval($expression);
} else if (preg_match(Language\Regex::EXPR_STRING, $expression)) {
return substr($expression, 1, strlen($expression) - 2);
} else if (preg_match(Language\Regex::EXPR_REGEX, $expression)) {
return $expression;
} else {
$match = array();
$length = preg_match(Language\Regex::LENGTH, $expression, $match);
if ($length) {
$expression = $match[1];
}
$result = false;
if ($expression[0] === Language\Token::ROOT){
list($result, $_) = \JsonPath\JsonPath::subtreeGet($root, $root, $expression);
}
else if ($expression[0] === Language\Token::CHILD) {
$expression[0] = Language\Token::ROOT;
list($result, $_) = \JsonPath\JsonPath::subtreeGet($root, $partial, $expression);
}
if ($result !== false) {
if ($length) {
if (is_array($result[0])) {
return (float) count($result[0]);
}
if (is_string($result[0])) {
return (float) strlen($result[0]);
}
return false;
}
if (is_float($result[0]) || is_int($result[0])) {
$result[0] = (float) $result[0];
}
return $result[0];
}
return $result;
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
/**
* Exception that is raised when a invalid value is given to the JsonObject
* constructor.
*
* @uses Exception
*/
class InvalidJsonException extends \Exception
{
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
/**
* Exception that is raised when a error is found in the given JSONPath
*
* @uses Exception
*/
class InvalidJsonPathException extends \Exception
{
private $token;
/**
* Class constructor
*
* @param string $token token related to the JSONPath error
*
* @return void
*/
public function __construct($token)
{
parent::__construct("Error in JSONPath near '" . $token . "'", 0, null);
}
}

View File

@@ -0,0 +1,338 @@
<?php
/**
* Copyright 2018 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
use JsonPath\InvalidJsonException;
use JsonPath\Operation;
/**
* This is a [JSONPath](http://goessner.net/articles/JsonPath/) implementation for PHP.
*
* This implementation features all elements in the specification except the `()` operator (in the spcecification there is the `$..a[(@.length-1)]`, but this can be achieved with `$..a[-1]` and the latter is simpler).
*
* On top of this it implements some extended features:
*
* * Regex match comparisons (p.e. `$.store.book[?(@.author =~ /.*Tolkien/)]`)
* * For the child operator `[]` there is no need to surround child names with quotes (p.e. `$.[store][book, bicycle]`) except if the name of the field is a non-valid javascript variable name.
* * `.length` can be used to get the length of a string, get the length of an array and to check if a node has children.
*
* Features
* ========
* This implementation has the following features:
*
* * Object oriented implementation.
* * __Get__, __set__ and __add__ operations.
* * Magic methods implemented:
* * `__get`: `$obj->{'$.json.path'}`.
* * `__set`: `$obj->{'$.json.path'} = $val`.
* * `__toString`: `echo $obj` prints the json representation of the JsonObject.
* * Not using `eval()`.
*
* Usage
* =====
* // $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->getArray();
*
* // add values
* $obj->add($jsonPath, $value[, $field]);
*
* // remove values
* $obj->remove($jsonPath, $field);
*
* SmartGet
* --------
*
* When creating a new instance of JsonObject, you can pass a second parameter to the constructor.
* This sets the behaviour of the instance to use SmartGet.
*
* What SmartGet does is to determine if the given JsonPath branches at some point, if it does it behaves as usual;
* otherwise, it will directly return the value pointed to by the given path (not the array containing it).
*
* $json = array(
* "a" => array(
* "b" => 3,
* "c" => 4
* )
* );
* $obj = new JsonObject($json, true);
* $obj->get('$.a.b'); // Returns int(3)
* $obj->get('$.a.*'); // Returns array(int(3), int(4))
*
*
* GetJsonObjects
* --------------
*
* Sometimes you need to access multiple values of a subobject that has a long prefix (p.e. `$.a.very.long.prefix.for.[*].object`), in this case you would first get said object
* and make a JsonObject of it and then access its properties.
*
* Now if you want to edit the object (set or add values) and want these changes to affect the original object, the way of doing this is by using
* `JsonObject::getJsonObjects($jsonpath)`. This method works the same way get does, but it will return the results as JsonObject instances containing a reference to the value in the source JsonObject.
*/
class JsonObject
{
private $jsonObject = null;
private $smartGet = false;
/**
* Class constructor.
* If $json is null the json object contained
* will be initialized empty.
*
* @param mixed $json json
* @param bool $smartGet enable smart get
*
* @return void
*/
function __construct($json = null, $smartGet = false)
{
if ($json === null) {
$this->jsonObject = array();
} else if (is_string($json)) {
$this->jsonObject = json_decode($json, true);
if ($this->jsonObject === null) {
throw new InvalidJsonException("string does not contain a valid JSON object.");
}
} else if (is_array($json)) {
$this->jsonObject = $json;
} else if (is_object($json)){
$this->jsonObject = json_decode(json_encode($json), true);
} else {
throw new InvalidJsonException("value does not encode a JSON object.");
}
$this->smartGet = $smartGet;
}
/**
* Syntactic sugar for toJson() method.
* Usage:
* $json = (string)$instance;
* or
* echo $instance;
*
* @param string $jsonPath jsonPath
*
* @return (false|array)
*/
function __toString()
{
return $this->getJson();
}
/**
* Syntactic sugar for get() method. The starting '$' is not needed (implicit)
* Usage: $obj->{'.json.path'};
*
* @param string $jsonPath jsonPath
*
* @return (false|array)
*/
function __get($jsonPath)
{
return $this->get($jsonPath);
}
/**
* Syntactic sugar for set() method. The starting '$' is not needed (implicit)
* Usage: $obj->{'.json.path'} = $value;
*
* @param string $jsonPath jsonPath
* @param mixed $value value
*
* @return JsonObject
*/
function __set($jsonPath, $value)
{
return $this->set($jsonPath, $value);
}
/**
* Returns the value of the json object as a PHP array.
*
*
* @return array
*/
public function &getValue()
{
return $this->jsonObject;
}
/**
* Returns the json object encoded as string.
* See http://php.net/manual/en/json.constants.php for more information on the $options bitmask.
*
* @param int $options json_encode options bitmask
*
* @return string
*/
public function getJson($options=0)
{
return json_encode($this->jsonObject, $options);
}
/**
* Returns an array containing references to the
* objects that match the JsonPath. If the result is
* empty returns false.
*
* If smartGet was set to true when creating the instance and
* the JsonPath given does not branch, it will return the value
* instead of an array of one element.
*
* @param string $jsonPath jsonPath
*
* @return mixed
*/
public function get($jsonPath)
{
list($result, $hasDiverged) = JsonPath::get($this->jsonObject, $jsonPath);
if ($this->smartGet && $result !== false && !$hasDiverged && is_array($result)) {
return $result[0];
}
return $result;
}
/**
* Return an array of new JsonObjects representing the results of the
* given JsonPath. These objects contain references to the elements in the
* original JsonObject.
*
* This is affected by smartGet the same way JsonObject::get is affected
* This can cause JsonObject to have actual values (not object/array) as root.
*
* This is useful when you want to work with a subelement of the root
* object and you want to edit (add, set, remove) values in that subelement
* and that these changes also affect the root object.
*
* @param string $jsonPath jsonPath
*
* @return mixed
*/
public function getJsonObjects($jsonPath)
{
list($result, $hasDiverged) = JsonPath::get($this->jsonObject, $jsonPath);
if ($result !== false) {
$objs = array();
foreach($result as &$value) {
$jsonObject = new JsonObject(null, $this->smartGet);
$jsonObject->jsonObject = &$value;
$objs[] = $jsonObject;
}
if ($this->smartGet && !$hasDiverged && is_array($result)) {
return $objs[0];
}
return $objs;
}
return $result;
}
/**
* Sets all elements that result from the $jsonPath query
* to $value. This method will create previously non-existent
* JSON objects if the path contains them (p.e. if quering '$.a'
* results in false, when setting '$.a.b' to a value '$.a' will be created
* as a result of this).
*
* This method returns $this to enable fluent
* interface.
*
*
* @param string $jsonPath jsonPath
* @param mixed $value value
*
* @return JsonObject
*/
public function set($jsonPath, $value)
{
list($result, $_) = JsonPath::get($this->jsonObject, $jsonPath, true);
if ($result !== false) {
foreach ($result as &$element) {
$element = $value;
}
}
return $this;
}
/**
* Append a new value to all json objects/arrays that match
* the $jsonPath path. If $field is not null, the new value
* will be added with $field as key (this will transform
* json arrays into objects). This method returns $this to
* enable fluent interface.
*
* @param string $jsonPath jsonPath
* @param mixed $value value
* @param string $field field
*
* @return JsonObject
*/
public function add($jsonPath, $value, $field=null)
{
list($result, $_) = JsonPath::get($this->jsonObject, $jsonPath, true);
foreach ($result as &$element) {
if (is_array($element)) {
if ($field == null) {
$element[] = $value;
}
else {
$element[$field] = $value;
}
}
}
return $this;
}
/**
* Remove $field from json objects/arrays that match
* $jsonPath path. This method returns $this to enable
* fluent interface.
*
* @param mixed $jsonPath jsonPath
* @param mixed $field field
*
* @return JsonObject
*/
public function remove($jsonPath, $field)
{
list($result, $_) = JsonPath::get($this->jsonObject, $jsonPath);
foreach ($result as &$element) {
if (is_array($element)) {
unset($element[$field]);
}
}
return $this;
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath;
use JsonPath\Expression;
use JsonPath\Language;
use JsonPath\Operation;
class JsonPath
{
public static function get(&$root, $jsonPath, $createInexistent = false)
{
return JsonPath::subtreeGet($root, $root, $jsonPath, $createInexistent);
}
public static function subtreeGet(&$root, &$partial, $jsonPath, $createInexistent = false)
{
$match = array();
if (preg_match(Language\Regex::ROOT_OBJECT, $jsonPath, $match) === 0) {
throw new \JsonPath\InvalidJsonPathException($jsonPath);
}
$hasDiverged = false;
$jsonPath = $match[1];
$selection = array(&$partial);
while (strlen($jsonPath) > 0 and count($selection) > 0) {
$newSelection = array();
$newHasDiverged = false;
if (preg_match(Language\Regex::CHILD_NAME, $jsonPath, $match)) {
$childName = $match[1];
foreach ($selection as &$partial) {
list($result, $newHasDiverged) = Operation\GetChild::apply($partial, $childName, $createInexistent);
$newSelection = array_merge($newSelection, $result);
}
if (empty($newSelection) && Language\Token::LENGTH === $childName) {
if (count($selection) > 1) {
foreach ($selection as $item) {
$newSelection[] = is_array($item) ? count($item) : strlen($item);
}
} else if (count($selection) == 1) {
$newSelection = is_array($selection[0]) ? count($selection[0]) : strlen($selection[0]);
}
}
if (empty($newSelection)) {
$selection = false;
break;
} else {
$jsonPath = $match[2];
}
} else if (Language\ChildSelector::match($jsonPath, $match)) {
$contents = $match[0];
foreach ($selection as &$partial) {
list($result, $newHasDiverged) = Operation\SelectChildren::apply($root, $partial, $contents, $createInexistent);
$newSelection = array_merge($newSelection, $result);
}
if (empty($newSelection)) {
$selection = false;
break;
} else {
$jsonPath = $match[1];
}
} else if (preg_match(Language\Regex::RECURSIVE_SELECTOR, $jsonPath, $match)) {
list($result, $newHasDiverged) = Operation\GetRecursive::apply($partial, $match[1]);
$newSelection = array_merge($newSelection, $result);
if (empty($newSelection)) {
$selection = false;
break;
} else {
$jsonPath = $match[2];
}
} else {
throw new \JsonPath\InvalidJsonPathException($jsonPath);
}
$selection = $newSelection;
$hasDiverged = $hasDiverged || $newHasDiverged;
}
return array($selection, $hasDiverged);
}
}

View File

@@ -0,0 +1,60 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Language;
class ChildSelector
{
public static function match($jsonPath, &$match, $offset=0)
{
if ($jsonPath[$offset] != Token::SELECTOR_BEGIN) {
return false;
}
$initialOffset = $offset;
$offset += 1;
$parenCount = 0;
$bracesCount = 1;
// $count is a reference to the counter of the $startChar type
$match = array();
while ($bracesCount > 0 and $parenCount >= 0) {
if (preg_match(Regex::NEXT_SUBEXPR, $jsonPath, $match, PREG_OFFSET_CAPTURE, $offset)) {
$c = $match[1][0];
if ($c === Token::EXPRESSION_BEGIN) {
$parenCount += 1;
} else if ($c === Token::EXPRESSION_END) {
$parenCount -= 1;
} else if ($c === Token::SELECTOR_BEGIN) {
$bracesCount += 1;
} else if ($c === Token::SELECTOR_END) {
$bracesCount -= 1;
}
$offset = $match[1][1] + 1;
} else {
break;
}
}
if ($bracesCount == 0 && $parenCount == 0) {
$match = array(
substr($jsonPath, $initialOffset + 1, $offset - $initialOffset - 2),
substr($jsonPath, $offset - $initialOffset)
);
return 1;
}
$match = array();
return 0;
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Language;
class Regex
{
// Root regex
const ROOT_OBJECT = '/^\$(.*)/';
// Child regex
const CHILD_NAME = '/^\.([\w\_\$^\d][\w\-\$]*|\*)(.*)/u';
const RECURSIVE_SELECTOR = '/^\.\.([\w\_\$^\d][\w\-\$]*|\*)(.*)/u';
// Array expressions
const ARRAY_INTERVAL = '/^(?:(-?\d*:-?\d*)|(-?\d*:-?\d*:-?\d*))$/';
const INDEX_LIST = '/^(-?\d+)(\s*,\s*-?\d+)*$/';
const LENGTH = '/^(.*)\.length$/';
// Object expression
const CHILD_NAME_LIST = '/^(?:([\w\_\$^\d][\w\-\$]*?|".*?"|\'.*?\')(\s*,\s*([\w\_\$^\d][\w\-\$]*|".*?"|\'.*?\'))*)$/u';
// Conditional expressions
const EXPR_STRING = '/^(?:\'(.*)\'|"(.*)")$/';
const EXPR_REGEX = '/^\/.*\/$/';
const BINOP_COMP = '/^(.+)\s*(==|!=|<=|>=|<|>|=\~)\s*(.+)$/';
const BINOP_OR = '/\s+(or|\|\|)\s+/';
const BINOP_AND = '/\s+(and|&&)\s+/';
const OP_NOT = '/^(not|!)\s+(.*)/';
const NEXT_SUBEXPR = '/.*?(\(|\)|\[|\])/';
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Language;
class Token
{
const ROOT = '$';
const CHILD = '@';
const SELECTOR_BEGIN = '[';
const SELECTOR_END = ']';
const BOOL_EXPR = '?';
const EXPRESSION_BEGIN = '(';
const EXPRESSION_END = ')';
const ALL = '*';
const COMA = ',';
const COLON = ':';
const COMP_EQ = '==';
const COMP_NEQ = '!=';
const COMP_LT = '<';
const COMP_GT = '>';
const COMP_LTE = '<=';
const COMP_GTE = '>=';
const COMP_RE_MATCH = '=~';
const VAL_TRUE = 'true';
const VAL_FALSE = 'false';
const VAL_NULL = 'null';
const LENGTH = 'length';
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Operation;
use JsonPath\Language;
class GetChild
{
public static function apply(&$jsonObject, $childName, $createInexistent = false)
{
if (!is_array($jsonObject)) {
return array(array(), false);
}
$result = array();
$hasDiverged = false;
if ($childName === Language\Token::ALL) {
$hasDiverged = true;
foreach ($jsonObject as $key => $_) {
$result[] = &$jsonObject[$key];
}
} else if (array_key_exists($childName, $jsonObject)) {
$result[] = &$jsonObject[$childName];
} else if ($createInexistent) {
$jsonObject[$childName] = array();
$result[] = &$jsonObject[$childName];
}
return array($result, $hasDiverged);
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Operation;
use JsonPath\Language;
class GetRecursive
{
public static function apply(&$jsonObject, $childName)
{
list($result, $_) = GetChild::apply($jsonObject, $childName);
if (is_array($jsonObject)) {
foreach ($jsonObject as &$item) {
list($localResult, $_) = GetRecursive::apply($item, $childName);
$result = array_merge($result, $localResult);
}
}
return array($result, true);
}
}

View File

@@ -0,0 +1,79 @@
<?php
/**
* Copyright 2021 Alessio Linares
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace JsonPath\Operation;
use JsonPath\Language;
use JsonPath\Expression;
class SelectChildren
{
public static function apply(&$root, &$partial, $contents, $createInexistent = false)
{
if (!is_array($partial)) {
return array(array(), false);
}
$result = array();
$hasDiverged = false;
$match = array();
$contentsLen = strlen($contents);
if ($contents === Language\Token::ALL) {
$hasDiverged = true;
foreach ($partial as $key => $item) {
$result[] = &$partial[$key];
}
} else if (preg_match(Language\Regex::CHILD_NAME_LIST, $contents, $match)) {
$names = array_map(
function($x) { return trim($x, " \t\n\r\0\x0B'\""); },
explode(Language\Token::COMA, $contents)
);
if (count($names) > 1) {
$hasDiverged = true;
}
$result = Expression\ChildNameList::evaluate($partial, $names, $createInexistent);
} else if (preg_match(Language\Regex::INDEX_LIST, $contents)) {
$indexes = array_map(
function($x) { return intval(trim($x)); },
explode(Language\Token::COMA, $contents)
);
if (count($indexes) > 1) {
$hasDiverged = true;
}
$result = Expression\IndexList::evaluate($partial, $indexes, $createInexistent);
} else if (preg_match(Language\Regex::ARRAY_INTERVAL, $contents, $match)) {
// end($match) has the matched group with the interval
$numbers = explode(Language\Token::COLON, end($match));
$hasDiverged = true;
$result = Expression\ArrayInterval::evaluate($partial, $numbers);
} else if ($contents[0] === Language\Token::BOOL_EXPR
&& $contents[1] === Language\Token::EXPRESSION_BEGIN
&& $contents[$contentsLen - 1] === Language\Token::EXPRESSION_END
) {
$hasDiverged = true;
$subexpr = substr($contents, 2, $contentsLen - 3);
foreach ($partial as &$child) {
if (Expression\BooleanExpression::evaluate($root, $child, $subexpr)) {
$result[] = &$child;
}
}
} else {
throw new \JsonPath\InvalidJsonPathException($contents);
}
return array($result, $hasDiverged);
}
}