{"id":17045701,"url":"https://github.com/remorhaz/php-json-path","last_synced_at":"2025-09-08T15:31:57.025Z","repository":{"id":62534649,"uuid":"135201216","full_name":"remorhaz/php-json-path","owner":"remorhaz","description":"JSONPath implementation in PHP.","archived":false,"fork":false,"pushed_at":"2024-07-02T12:37:52.000Z","size":727,"stargazers_count":13,"open_issues_count":5,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-12-27T05:06:33.750Z","etag":null,"topics":["json","jsonpath","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/remorhaz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-28T19:28:07.000Z","updated_at":"2024-09-07T04:27:09.000Z","dependencies_parsed_at":"2024-11-07T14:00:46.467Z","dependency_job_id":null,"html_url":"https://github.com/remorhaz/php-json-path","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remorhaz%2Fphp-json-path","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remorhaz%2Fphp-json-path/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remorhaz%2Fphp-json-path/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/remorhaz%2Fphp-json-path/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/remorhaz","download_url":"https://codeload.github.com/remorhaz/php-json-path/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232320250,"owners_count":18504974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","jsonpath","php"],"created_at":"2024-10-14T09:38:08.836Z","updated_at":"2025-01-03T10:10:28.410Z","avatar_url":"https://github.com/remorhaz.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PHP JSONPath\n[![Latest Stable Version](https://poser.pugx.org/remorhaz/php-json-path/version)](https://packagist.org/packages/remorhaz/php-json-path)\n[![Build](https://github.com/remorhaz/php-json-path/actions/workflows/build.yml/badge.svg)](https://github.com/remorhaz/php-json-path/actions/workflows/build.yml)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/remorhaz/php-json-path/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/remorhaz/php-json-path/?branch=master)\n[![codecov](https://codecov.io/gh/remorhaz/php-json-path/branch/master/graph/badge.svg)](https://codecov.io/gh/remorhaz/php-json-path)\n[![Mutation testing badge](https://img.shields.io/endpoint?style=flat\u0026url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fremorhaz%2Fphp-json-path%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/remorhaz/php-json-path/master)\n[![Total Downloads](https://poser.pugx.org/remorhaz/php-json-path/downloads)](https://packagist.org/packages/remorhaz/php-json-path)\n[![License](https://poser.pugx.org/remorhaz/php-json-path/license)](https://packagist.org/packages/remorhaz/php-json-path)\n\nJSONPath is a simple query language for JSON documents, inspired by XPath for XML and originally designed by [Stefan Goessner](https://goessner.net/articles/JsonPath/).\n\n## Features\n- Accepts encoded JSON strings as well as decoded PHP data as input, supports both representations in output.\n- Selects, deletes or replaces parts of JSON document using JSONPath queries.\n- Recognizes definite/indefinite JSONPath queries without executing them.\n- Transforms indefinite JSONPath query to set of definite queries for given JSON document.\n\n## Requirements\n- PHP 8\n- [JSON extension](https://www.php.net/manual/en/book.json.php) (ext-json) - required by [remorhaz/php-json-data](https://github.com/remorhaz/php-json-data) that is used to access JSON documents.\n- [Internationalization functions](https://www.php.net/manual/en/book.intl.php) (ext-intl)\n- [Tokenizer extension](https://www.php.net/manual/en/book.tokenizer.php) (ext-tokenizer) - required by [nikic/php-parser](https://github.com/nikic/PHP-Parser) that is used for code generation.\n\n## Installation\nYou can use Composer to install this package:\n```\ncomposer require remorhaz/php-json-path\n```\n\n## Usage\n### Accessing JSON document\nYou can create accessible JSON document either from encoded JSON string or from decoded JSON data using corresponding _node value factory_:\n```php\nuse Remorhaz\\JSON\\Data\\Value\\EncodedJson;\nuse Remorhaz\\JSON\\Data\\Value\\DecodedJson;\n\n// Creating document from JSON-encoded string:\n$encodedValueFactory = EncodedJson\\NodeValueFactory::create();\n$encodedJson = '{\"a\":1}';\n$document1 = $encodedValueFactory-\u003ecreateValue($encodedJson);\n\n// Creating document from decoded JSON data:\n$decodedValueFactory = DecodedJson\\NodeValueFactory::create();\n$decodedJson = (object) ['a' =\u003e 1];\n$document2 = $decodedValueFactory-\u003ecreateValue($decodedJson);\n```\n\n### Creating query\nYou should use _query factory_ to create query from JSONPath expression:\n```php\nuse Remorhaz\\JSON\\Path\\Query\\QueryFactory;\n\n$queryFactory = QueryFactory::create();\n\n// Creating query that selects all 'a' properties from any document:\n$query = $queryFactory-\u003ecreateQuery('$..a');\n```\n_Definite_ query is the query that defines exactly one path in document. If query includes any filters, wildcards or deep children scan, it is considered _indefinite_.\n\n_Addressable_ query is the query that returns unprocessed part(s) of the document. If query returns an aggregate function result, it is considered _non-addressable_.\n### Processing query\nYou should use an instance of _query processor_ to execute queries on given JSON documents:\n```php\nuse Remorhaz\\JSON\\Path\\Processor\\Processor;\n\n$processor = Processor::create();\n```\n\n#### Selecting part of a JSON document\nThere are two ways to select part of JSON document using JSONPath query:\n\n1. You can get all matching parts in array, using `::select()` method. This works with both _definite_ and _indefinite_ queries. You will get empty array if none of document parts matches your query.\n2. You can get exactly one matching part, using `::selectOne()` method. Note that this works only with _definite_ queries. You will get an exception if your query is indefinite.\n\n```php\nuse Remorhaz\\JSON\\Data\\Value\\EncodedJson;\nuse Remorhaz\\JSON\\Path\\Processor\\Processor;\nuse Remorhaz\\JSON\\Path\\Query\\QueryFactory;\n\n$processor = Processor::create()\n$queryFactory = QueryFactory::create();\n$encodedValueFactory = EncodedJson\\NodeValueFactory::create();\n\n$document = $encodedValueFactory-\u003ecreateValue('{\"a\":{\"a\":1,\"b\":2}');\n\n// Selecting all 'a' properties (indefinite query, values exist):\n$query1 = $queryFactory-\u003ecreateQuery('$..a');\n$result1 = $processor-\u003eselect($query1, $document);\nvar_dump($result1-\u003eselect()); // array: ['{\"a\":1,\"b\":2}', '1']\n\n// Selecting single 'b' property nested in 'a' property (definite query, value exists):\n$query2 = $queryFactory-\u003ecreateQuery('$.a.b');\n$result2 = $processor-\u003eselectOne($query2, $document);\nvar_dump($result2-\u003eexists()); // boolean: true\nvar_dump($result2-\u003edecode()); // integer: 2\n\n// Selecting single 'b' property (definite query, value doesn't exist):\n$query3 = $queryFactory-\u003ecreateQuery('$.b');\n$result3 = $processor-\u003eselectOne($query3, $document);\nvar_dump($result3-\u003eexists()); // boolean: false\nvar_dump($result3-\u003edecode()); // throws exception\n```\nNote that you can either encode result(s) of a selection to JSON string(s) or decode them to raw PHP data. Before accessing a result of `::selectOne()` you can check it's existence with `::exists()` method to avoid exception.\n\n#### Deleting part of a JSON document\nTo delete part(s) of a JSON document use `::delete()` method. It works only with _addressable_ queries. You will get an exception if your query is non-addressable. If none of document parts match the query you will get the document unchanged. Special case is deleting root of a document - in this case you will get non-existing result.\n```php\nuse Remorhaz\\JSON\\Data\\Value\\EncodedJson;\nuse Remorhaz\\JSON\\Path\\Processor\\Processor;\nuse Remorhaz\\JSON\\Path\\Query\\QueryFactory;\n\n$processor = Processor::create()\n$queryFactory = QueryFactory::create();\n$encodedValueFactory = EncodedJson\\NodeValueFactory::create();\n\n$document = $encodedValueFactory-\u003ecreateValue('{\"a\":{\"a\":1,\"b\":2}');\n\n// Deleting all 'b' properties (value exists):\n$query1 = $queryFactory-\u003ecreateQuery('$..b');\n$result1 = $processor-\u003edelete($query1, $document);\nvar_dump($result1-\u003eexists()); // boolean: true\nvar_dump($result1-\u003eencode()); // '{\"a\":{\"a\":1}}'\n\n// Deleting all 'c' properties (value doesn't exist):\n$query2 = $queryFactory-\u003ecreateQuery('$..c');\n$result2 = $processor-\u003edelete($query2, $document);\nvar_dump($result1-\u003eexists()); // boolean: true\nvar_dump($result1-\u003eencode()); // '{\"a\":{\"a\":1,\"b\":2}}'\n\n// Deleting root of the document:\n$query3 = $queryFactory-\u003ecreateValue('$');\n$result3 = $processor-\u003edelete($query3, $document);\nvar_dump($result3-\u003eexists()); // boolean: false\nvar_dump($result3-\u003eencode()); // throws exception\n```\n\n#### Replacing the part of a JSON document with another JSON document\nTo replace part(s) of a JSON document with another JSON document use `::replace()` method. It works only with _addressable_ queries. You will get an exception if your query is non-addressable. If none of document parts match the query you will get the document unchanged. If the query matches nested parts of a document, you will also get an exception.\n\n```php\nuse Remorhaz\\JSON\\Data\\Value\\EncodedJson;\nuse Remorhaz\\JSON\\Path\\Processor\\Processor;\nuse Remorhaz\\JSON\\Path\\Query\\QueryFactory;\n\n$processor = Processor::create()\n$queryFactory = QueryFactory::create();\n$encodedValueFactory = EncodedJson\\NodeValueFactory::create();\n\n$document1 = $encodedValueFactory-\u003ecreateValue('{\"a\":{\"a\":1,\"b\":2}');\n$document2 = $encodedValueFactory-\u003ecreateValue('{\"c\":3}');\n\n// Replacing 'a' property (value exists):\n$query1 = $queryFactory-\u003ecreateQuery('$.a');\n$result1 = $processor-\u003ereplace($query1, $document1, $document2);\nvar_dump($result1-\u003eencode()); // string: '{\"a\":{\"c\":3}}'\n\n// Replacing all 'c' properties (value doesn't exist)\n$query2 = $queryFactory-\u003ecreateQuery('$..c');\n$result2 = $processor-\u003ereplace($query2, $document1, $document2);\nvar_dump($result2-\u003eencode()); // string: '{\"a\":{\"a\":1,\"b\":2}'\n\n// Replacing all 'a' properties (values are nested):\n$query3 = $queryFactory-\u003ecreateQuery('$..a');\n$result3 = $processor-\u003ereplace($query3, $document1, $document2); // throws exception\n```\n\n## Grammar\nAll JSONPath queries start with abstract `$` symbol that denotes outer level object. Internal structure can be \nmatched with child operators and filters:\n\n|Operation|Description|\n|---|---|\n|`$`|Root object of the JSON document.|\n|`.a`|Property `a` of current object (dot-notation).|\n|`..a`|Properties `a` of current and all it's nested objects.|\n|`['a']`|Property `a` of current object (bracket-notation).|\n|`['a', 'b']`|Properties `a` and `b` of current object.|\n|`[1, 3]`|Indexes `1` and `3` of current array.|\n|`[3:10:2]`|Sequence of indexes from `3` to `10` with step `2`.|\n|`*`|Wildcard that matches any property of current object / index of current array.|\n|`[?(\u003cexpression\u003e)]`|Filters values by expression.|\n|`.length()`|Aggregate function.|\n\n### Child operators\nThere are two notations for selecting structure children: _dot_-notation and _bracket_-notation.\n\nDot-notation allows to select either exactly one property or all children (using a wildcard). _Double-dot_ notation\nwalks through the JSON structure recursively.\n\n|Example|Description|\n|---|---|\n|`$.a`|Selects property `a` of a root object.|\n|`$.*`|Selects all properties of a root objects or all elements of a root array.|\n|`$..a`|Selects property `a` of all objects recursively.|\n|`$..*`|Selects all properties/elements of all objects/arrays recursively.|\n\nBracket-notation allows to select a set of properties/elements:\n\n|Example|Description|\n|---|---|\n|`$['a', 'b']`|Selects properties `a` and `b` of a root object.|\n|`$[2, 3]`|Selects elements `2` and `3` from a root array.|\n|`$[3:10:2]`|Selects a sequence of elements from `3` up to `10` with step `2`. This equivalent query is `$[3, 5, 7, 9]`. The notation is same as in Python.|\n|`$[*]`|Select all children. Same as `$.*`.|\n\n### Aggregate functions\nAggregate functions can be appended to any path in query and it will return calculated value.\n\n|Function|Description|\n|---|---|\n|`.min()`|Returns minimal number from current array.|\n|`.max()`|Returns maximal number from current array.|\n|`.length()`|Returns amount of elements in current array.|\n|`.avg()`|Returns average value from numbers in current array.|\n|`.stddev()`|Returns standard deviation from numbers in current array.|\n\nThe set of aggregate functions and idea itself is taken from [Java implementation](https://github.com/json-path/JsonPath).\n\n### Filter expressions\nWhen filter is being applied to nodeset, it leaves only those nodes for which the expression evaluates to true.\n\n|Example|Description|\n|---|---|\n|`$..a[?(@.b)]`|Selects all properties `a` that contain objects with property `b`.|\n|`$..a[?(@.b \u003e 2)]`|Selects all properties `a` that contain objects with property `b` that is number greater than `2`.|\n|`$..a[?(true)]`|Boolean `true` is the only literal that evaluates to `true`; so this query is equivalent to `$..a`.|\n|`$..a[?(1)]`|**Attention!** This evaluates to `false`, selecting nothing, because no automatic typecasting is performed.|\n\n#### Filter context\nExpression `@` points to the value to which the filter was applied.\n\n#### Operators\n_Comparison operators_ can be used to compare value with another value or with a literal. Supported operators are: \n`==`, `!=`, `\u003e`, `\u003e=`, `\u003c` and `\u003c=`. Brackets can be used for _grouping_, and _logical operators_ `\u0026\u0026`, `||` and `!` \nare also supported. _Regular expressions_ can be matched using `=~` operator.\n\n|Example|Description|\n|---|---|\n|`$..a[?(@.b == @.c)]`|Selects property `a` of any object that is object with properties `b` and `c` with equal values.|\n|`$..a[?(@.b || (@.c \u003c= 1))]`|Selects property `a` of any object that is object with either property `b` or property `c` with int/float value lesser or equal to `1`.|\n|`$..a[?(@.b =~ /^b/i)]`|Selects property `a` of any object that is object with string property `b` that starts from `b` or `B`.|\n\n### Original definition\nGoessner described JSONPath grammar with providing a set of example queries on JSON sample. Here's his original \ndata sample:\n```json\n{ \"store\": {\n    \"book\": [ \n      { \"category\": \"reference\",\n        \"author\": \"Nigel Rees\",\n        \"title\": \"Sayings of the Century\",\n        \"price\": 8.95\n      },\n      { \"category\": \"fiction\",\n        \"author\": \"Evelyn Waugh\",\n        \"title\": \"Sword of Honour\",\n        \"price\": 12.99\n      },\n      { \"category\": \"fiction\",\n        \"author\": \"Herman Melville\",\n        \"title\": \"Moby Dick\",\n        \"isbn\": \"0-553-21311-3\",\n        \"price\": 8.99\n      },\n      { \"category\": \"fiction\",\n        \"author\": \"J. R. R. Tolkien\",\n        \"title\": \"The Lord of the Rings\",\n        \"isbn\": \"0-395-19395-8\",\n        \"price\": 22.99\n      }\n    ],\n    \"bicycle\": {\n      \"color\": \"red\",\n      \"price\": 19.95\n    }\n  }\n}\n```\nAnd here are his original example queries with result descriptions:\n\n|Query|Result|Supported|Comments|\n|---|---|---|---|\n|`$.store.book[*].author`|The authors of all books in the store.|Yes| |\n|`$..author`|All authors.|Yes| |\n|`$.store.*`|All things in store, which are some books and a red bicycle.|Yes| |\n|`$.store..price`|The price of everything in the store.|Yes| |\n|`$..book[2]`|The third book.|Yes| |\n|`$..book[(@.length-1)]`|The last book in order.|No|Original implementation uses _underlying script engine_ (JavaScript, in his case) in expressions. In case of PHP allowing to call arbitrary code from expression is unsafe, so script expressions are not implemented.|\n|`$..book[-1:]`|The last book in order.|Yes| |\n|`$..book[0,1]`|The first two books.|Yes| |\n|`$..book[:2]`|The first two books.|Yes| |\n|`$..book[?(@.isbn)]`|Filter all books with isbn number.|Yes| |\n|`$..book[?(@.price\u003c10)]`|Filter all books cheapier than 10.|Yes| |\n|`$..*`|All members of JSON structure.|Yes| |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremorhaz%2Fphp-json-path","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremorhaz%2Fphp-json-path","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremorhaz%2Fphp-json-path/lists"}