Skip to content

SoftCreatR/JSONPath

Repository files navigation

JSONPath for PHP 8.5+

BuildLatest ReleaseMIT licensedPlant TreeCodecov branch

This is a JSONPath implementation for PHP that targets the de facto comparison suite/RFC semantics while keeping the API small, cached, and eval-free.

Highlights

  • PHP 8.5+ only, with enums/readonly tokens and no eval.
  • Works with arrays, objects, and ArrayAccess/traversables in any combination.
  • Unions cover slices/queries/wildcards/multi-key strings (quoted or unquoted); negative indexes and escaped bracket notation are supported.
  • Filters support path-to-path/root comparisons, regex, in/nin/!in, deep equality, and RFC-style null existence/value handling.
  • Tokenized parsing with internal caching; lightweight manual runner to try bundled examples quickly.

Installation

Requires PHP 8.5 or newer.

composer require softcreatr/jsonpath:"^1.0"

Development

Useful commands:

composer exec phpunit composer phpstan composer cs

JSONPath Examples

JSONPathResult
$.store.books[*].authorthe authors of all books in the store
$..authorall authors
$.store..pricethe price of everything in the store.
$..books[2]the third book
$..books[(@.length-1)]the last book in order.
$..books[-1:]the last book in order.
$..books[0,1]the first two books
$..books[title,year]multiple keys in a union
$..books[:2]the first two books
$..books[::2]every second book starting from first one
$..books[1:6:3]every third book starting from 1 till 6
$..books[?(@.isbn)]filter all books with isbn number
$..books[?(@.price<10)]filter all books cheaper than 10
$..books.lengththe amount of books
$..*all elements in the data (recursively extracted)

Expression syntax

SymbolDescription
$The root object/element (not strictly necessary)
@The current object/element
. or []Child operator
..Recursive descent
*Wildcard. All child elements regardless their index.
[,]Array indices as a set
[start:end:step]Array slice operator borrowed from ES4/Python.
?()Filters a result set by a comparison expression
()Uses the result of a comparison expression as the index

PHP Usage

Using arrays

<?phprequire_once__DIR__ . '/vendor/autoload.php'; $data = ['people' => [ ['name' => 'Sascha'], ['name' => 'Bianca'], ['name' => 'Alexander'], ['name' => 'Maximilian'], ]]; print_r((new \Flow\JSONPath\JSONPath($data))->find('$.people.*.name')->getData()); /*Array( [0] => Sascha [1] => Bianca [2] => Alexander [3] => Maximilian)*/

Using objects

<?phprequire_once__DIR__ . '/vendor/autoload.php'; $data = json_decode('{"name":"Sascha Greuel","birthdate":"1987-12-16","city":"Gladbeck","country":"Germany"}', false); print_r((new \Flow\JSONPath\JSONPath($data))->find('$')->getData()[0]); /*stdClass Object( [name] => Sascha Greuel [birthdate] => 1987-12-16 [city] => Gladbeck [country] => Germany)*/

Magic method access

The options flag JSONPath::ALLOW_MAGIC will instruct JSONPath when retrieving a value to first check if an object has a magic __get() method and will call this method if available. This feature is iffy and not very predictable as:

  • wildcard and recursive features will only look at public properties and can't smell which properties are magically accessible
  • there is no property_exists check for magic methods so an object with a magic __get() will always return true when checking if the property exists
  • any errors thrown or unpredictable behavior caused by fetching via __get() is your own problem to deal with
<?phpuseFlow\JSONPath\JSONPath; $myObject = (newFoo())->get('bar'); $jsonPath = newJSONPath($myObject, JSONPath::ALLOW_MAGIC);

Script expressions

Script execution is intentionally not supported:

  • It would require eval, which we avoid.
  • Behavior would diverge across languages and defeat having a portable expression syntax.

Supported filter/query patterns (200+ cases covered in the comparison suite):

[?(@._KEY_ _OPERATOR_ _VALUE_)] Operators: ==, =, !=, <>, !==, <, >, <=, >=, =~, in, nin, !in Examples: [?(@.title == "A string")] // equality [?(@.title = "A string")] // SQL-style equals [?(@.price < 10)] // numeric comparisons [?(@.title =~ /^a(nother)?/i)] // regex [?(@.title in ["A","B"])] // membership [?(@.title nin ["A"])] // not in [?(@.title !in ["A"])] // alternate not in [?(@.key == @.other)] // path-to-path comparison [?(@.key == $.rootValue)] // root reference [?(@)] or [?(@==@)] // truthy/tautology [?(@.length)] // existence checks [?(@['weird-key']=="ok")] // bracket-escaped keys and negative indexes 

A full list of (un)supported filter/query patterns can be found in the JSONPath Comparison Cheatsheet.

Similar projects

FlowCommunications/JSONPath is the predecessor of this library by Stephen Frank

Other / Similar implementations can be found in the Wiki.

Changelog

A list of changes can be found in the CHANGELOG.md file.

License 🌳

MIT © 1-2.dev

This package is Treeware. If you use it in production, then we ask that you buy the world a tree to thank us for our work. By contributing to the ecologi project, you’ll be creating employment for local families and restoring wildlife habitats.

Contributors ✨

Sascha
Sascha Greuel
James
James Lucas
Fabian
Fabian Blechschmidt
Mikko
Mikko Pesari
warlof/
warlof
Sergey
Sergey G
Alexandru
Alexandru Pătrănescu
Oleg
Oleg Andreyev
Remy
Remy Suen
esomething/
esomething