diff --git a/src/JsonPath.php b/src/JsonPath.php index de4d5bc..4ccf98b 100644 --- a/src/JsonPath.php +++ b/src/JsonPath.php @@ -16,18 +16,38 @@ public function __construct(private $query) public function find($json) { $result_node_list = run($json, $this->root_node); - return array_map(fn(Node $node) => $node->value, $result_node_list); + return array_map(fn (Node $node) => $node->value, $result_node_list); + } + + protected function convert_path_segment_to_string($segment) + { + if (is_string($segment)) { + if ($segment === '$') { + return $segment; + } + return "['{$segment}']"; + } + return "[{$segment}]"; } public function paths($json) { $result_node_list = run($json, $this->root_node); return array_map( - fn(Node $node) => [ + fn (Node $node) => [ 'value' => $node->value, - 'path' => $node->path, + 'path' => implode(array_map(fn ($segment) => $this->convert_path_segment_to_string($segment), $node->path)), ], $result_node_list, ); } + + public function pathSegments($json) + { + $result_node_list = run($json, $this->root_node); + return array_map(fn (Node $node) => [ + 'value' => $node->value, + 'segments' => array_slice($node->path, 1) + ], $result_node_list); + } } diff --git a/src/parser.php b/src/parser.php index f732e88..b56eefe 100644 --- a/src/parser.php +++ b/src/parser.php @@ -4,6 +4,6 @@ function run($json, $query): array { - $root_node = create_node($json, '$'); + $root_node = create_node($json, ['$']); return apply_root($query, $root_node); } diff --git a/src/types/node.php b/src/types/node.php index f116422..7b7c939 100644 --- a/src/types/node.php +++ b/src/types/node.php @@ -6,10 +6,12 @@ class Node { - public function __construct(public mixed $value, public string $path) {} + public function __construct(public mixed $value, public array $path) + { + } } -function create_node(mixed $json, string $path): Node +function create_node(mixed $json, array $path): Node { return new Node($json, $path); } @@ -18,12 +20,12 @@ function add_member_path(Node $base, mixed $new_value, string $member_name): Nod { $escaped_member_name = escape_member_name($member_name); - return create_node($new_value, "{$base->path}['{$escaped_member_name}']"); + return create_node($new_value, [...$base->path, $escaped_member_name]); } function add_index_path(Node $base, mixed $new_value, int $index): Node { - return create_node($new_value, "{$base->path}[{$index}]"); + return create_node($new_value, [...$base->path, $index]); } function is_node($node) diff --git a/tests/utils/TraverseDescendantTest.php b/tests/utils/TraverseDescendantTest.php index c53f1e2..7ee3567 100644 --- a/tests/utils/TraverseDescendantTest.php +++ b/tests/utils/TraverseDescendantTest.php @@ -3,25 +3,26 @@ declare(strict_types=1); use Loilo\JsonPath\Node; + use function Loilo\JsonPath\create_node; use function Loilo\JsonPath\traverse_descendant; describe('traverseDescendant', function () { test('empty object traverses empty', function () { - $node = create_node((object) [], ''); + $node = create_node((object) [], []); expect( array_map( - fn(Node $node) => $node->value, + fn (Node $node) => $node->value, traverse_descendant($node), ), )->toEqual([(object) []]); }); test('nested arrays traverse correctly', function () { - $node = create_node([[[1]], [2]], ''); + $node = create_node([[[1]], [2]], []); expect( array_map( - fn(Node $node) => $node->value, + fn (Node $node) => $node->value, traverse_descendant($node), ), )->toEqual([[[[1]], [2]], [[1]], [1], 1, [2], 2]);