diff --git a/components/json_path.rst b/components/json_path.rst index f4a5f8a2d7d..ec5db0e8e74 100644 --- a/components/json_path.rst +++ b/components/json_path.rst @@ -6,13 +6,15 @@ The JsonPath Component The JsonPath component was introduced in Symfony 7.3 as an :doc:`experimental feature `. -The JsonPath component provides a powerful way to query and extract data from -JSON structures. It implements the `RFC 9535 - JSONPath`_ -standard, allowing you to navigate complex JSON data with ease. +The JsonPath component lets you query and extract data from JSON structures. +It implements the `RFC 9535 – JSONPath`_ standard, allowing you to navigate +complex JSON data. -Just as the :doc:`DomCrawler component ` allows you to navigate and query HTML/XML documents -using XPath, the JsonPath component provides a similar experience to traverse and search JSON structures -using JSONPath expressions. The component also offers an abstraction layer for data extraction. +Similar to the :doc:`DomCrawler component `, which lets +you navigate and query HTML or XML documents with XPath, the JsonPath component +offers the same convenience for traversing and searching JSON structures through +JSONPath expressions. The component also provides an abstraction layer for data +extraction. Installation ------------ @@ -29,8 +31,8 @@ Usage ----- To start querying a JSON document, first create a :class:`Symfony\\Component\\JsonPath\\JsonCrawler` -object from a JSON string. For the following examples, we'll use this sample -"bookstore" JSON data:: +object from a JSON string. The following examples use this sample "bookstore" +JSON data:: use Symfony\Component\JsonPath\JsonCrawler; @@ -75,8 +77,8 @@ object from a JSON string. For the following examples, we'll use this sample $crawler = new JsonCrawler($json); -Once you have the crawler instance, use its :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method to start querying -the data. This method always returns an array of matching values. +Once you have the crawler instance, use its :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` +method to start querying the data. This method returns an array of matching values. Querying with Expressions ------------------------- @@ -87,24 +89,26 @@ to the :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method. Accessing a Specific Property ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Use dot-notation for object keys and square brackets for array indices. The root +Use dot notation for object keys and square brackets for array indices. The root of the document is represented by ``$``:: - // Get the title of the first book in the store + // get the title of the first book in the store $titles = $crawler->find('$.store.book[0].title'); // $titles is ['Sayings of the Century'] -While dot-notation is common, JSONPath offers alternative syntaxes which can be more flexible. For instance, bracket notation (`['...']`) is required if a key contains spaces or special characters:: +Dot notation is the default, but JSONPath provides other syntaxes for cases where +it doesn't work. Use bracket notation (``['...']``) when a key contains spaces +or special characters:: - // This is equivalent to the previous example and works with special keys + // this is equivalent to the previous example $titles = $crawler->find('$["store"]["book"][0]["title"]'); - // You can also build the query programmatically for more complex scenarios - use Symfony\Component\JsonPath\JsonPath; + // this expression requires brackets because some keys use dots or spaces + $titles = $crawler->find('$["store"]["book collection"][0]["title.original"]'); - $path = (new JsonPath())->key('store')->key('book')->first()->key('title'); - $titles = $crawler->find($path); + // you can combine both notations + $titles = $crawler->find('$["store"].book[0].title'); Searching with the Descendant Operator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -112,7 +116,7 @@ Searching with the Descendant Operator The descendant operator (``..``) recursively searches for a given key, allowing you to find values without specifying the full path:: - // Get all authors from anywhere in the document + // get all authors from anywhere in the document $authors = $crawler->find('$..author'); // $authors is ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'John Ronald Reuel Tolkien'] @@ -120,113 +124,114 @@ you to find values without specifying the full path:: Filtering Results ~~~~~~~~~~~~~~~~~ -JSONPath includes a powerful filter syntax (``?()``) to select items -based on a condition. The current item within the filter is referenced by ``@``:: +JSONPath includes a filter syntax (``?(expression)``) to select items based on +a condition. The current item within the filter is referenced by ``@``:: - // Get all books with a price less than 10 + // get all books with a price less than 10 $cheapBooks = $crawler->find('$.store.book[?(@.price < 10)]'); - /* - $cheapBooks contains two book objects: - the one by "Nigel Rees" and the one by "Herman Melville" - */ - Building Queries Programmatically --------------------------------- -For more dynamic or complex query building, you can use the fluent API provided -by the :class:`Symfony\\Component\\JsonPath\\JsonPath` class. This allows you -to construct a query object step-by-step. The ``JsonPath`` object can then be -passed to the crawler's :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method. +For more dynamic or complex query building, use the fluent API provided +by the :class:`Symfony\\Component\\JsonPath\\JsonPath` class. This lets you +construct a query object step by step. The ``JsonPath`` object can then be passed +to the crawler's :method:`Symfony\\Component\\JsonPath\\JsonCrawler::find` method. The main advantage of the programmatic builder is that it automatically handles -the correct escaping of keys and values, preventing syntax errors:: +escaping of keys and values, preventing syntax errors:: use Symfony\Component\JsonPath\JsonPath; $path = (new JsonPath()) - ->key('store') // Selects the 'store' key - ->key('book') // Then the 'book' key - ->index(1); // Then the item at index 1 (the second book) + ->key('store') // selects the 'store' key + ->key('book') // then the 'book' key + ->index(1); // then the second item (indexes start at 0) - // The created $path object is equivalent to the string '$["store"]["book"][1]' + // the created $path object is equivalent to the string '$["store"]["book"][1]' $book = $crawler->find($path); // $book contains the book object for "Sword of Honour" -The :class:`Symfony\\Component\\JsonPath\\JsonPath` class provides several methods to build your query: +The :class:`Symfony\\Component\\JsonPath\\JsonPath` class provides several +methods to build your query: * :method:`Symfony\\Component\\JsonPath\\JsonPath::key` - Adds a key selector. The key name will be properly escaped:: + Adds a key selector. The key name is properly escaped:: - // Creates the path '$["key\"with\"quotes"]' - $path = (new JsonPath())->key('key"with"quotes'); + // creates the path '$["key\"with\"quotes"]' + $path = (new JsonPath())->key('key"with"quotes'); * :method:`Symfony\\Component\\JsonPath\\JsonPath::deepScan` - Adds the descendant operator ``..`` to perform a recursive search from the - current point in the path:: + Adds the descendant operator ``..`` to perform a recursive search from the + current point in the path:: - // Get all prices in the store: '$["store"]..["price"]' - $path = (new JsonPath())->key('store')->deepScan()->key('price'); + // get all prices in the store: '$["store"]..["price"]' + $path = (new JsonPath())->key('store')->deepScan()->key('price'); * :method:`Symfony\\Component\\JsonPath\\JsonPath::all` - Adds the wildcard operator ``[*]`` to select all items in an array or object:: + Adds the wildcard operator ``[*]`` to select all items in an array or object:: - // Creates the path '$["store"]["book"][*]' + // creates the path '$["store"]["book"][*]' $path = (new JsonPath())->key('store')->key('book')->all(); * :method:`Symfony\\Component\\JsonPath\\JsonPath::index` - Adds an array index selector. + Adds an array index selector. Index numbers start at ``0``. * :method:`Symfony\\Component\\JsonPath\\JsonPath::first` / :method:`Symfony\\Component\\JsonPath\\JsonPath::last` - Shortcuts for ``index(0)`` and ``index(-1)`` respectively:: + Shortcuts for ``index(0)`` and ``index(-1)`` respectively:: - // Get the last book: '$["store"]["book"][-1]' - $path = (new JsonPath())->key('store')->key('book')->last(); + // get the last book: '$["store"]["book"][-1]' + $path = (new JsonPath())->key('store')->key('book')->last(); * :method:`Symfony\\Component\\JsonPath\\JsonPath::slice` - Adds an array slice selector ``[start:end:step]``:: + Adds an array slice selector ``[start:end:step]``:: - // Get books from index 1 up to (but not including) index 3 - // Creates the path '$["store"]["book"][1:3]' - $path = (new JsonPath())->key('store')->key('book')->slice(1, 3); + // get books from index 1 up to (but not including) index 3 + // creates the path '$["store"]["book"][1:3]' + $path = (new JsonPath())->key('store')->key('book')->slice(1, 3); - // Get every second book from the first four books - // Creates the path '$["store"]["book"][0:4:2]' - $path = (new JsonPath())->key('store')->key('book')->slice(0, 4, 2); + // get every second book from the first four books + // creates the path '$["store"]["book"][0:4:2]' + $path = (new JsonPath())->key('store')->key('book')->slice(0, 4, 2); * :method:`Symfony\\Component\\JsonPath\\JsonPath::filter` - Adds a filter expression. The expression string is the part that goes inside - the ``?()`` syntax:: + Adds a filter expression. The expression string is the part that goes inside + the ``?()`` syntax:: - // Get expensive books: '$["store"]["book"][?(@.price > 20)]' - $path = (new JsonPath()) - ->key('store') - ->key('book') - ->filter('@.price > 20'); + // get expensive books: '$["store"]["book"][?(@.price > 20)]' + $path = (new JsonPath()) + ->key('store') + ->key('book') + ->filter('@.price > 20'); Advanced Querying ----------------- For a complete overview of advanced operators like wildcards and functions within -filters, please refer to the `Querying with Expressions`_ section above. All these -features are supported and can be combined with the programmatic builder where +filters, refer to the `Querying with Expressions`_ section above. All these +features are supported and can be combined with the programmatic builder when appropriate (e.g., inside a ``filter()`` expression). Error Handling -------------- -The component will throw specific exceptions for invalid input or queries: +The component throws specific exceptions for invalid input or queries: + +* :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidArgumentException`: + Thrown if the input to the ``JsonCrawler`` constructor is not a valid JSON string; +* :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidJsonStringInputException`: + Thrown during a ``find()`` call if the JSON string is malformed (e.g., syntax error); +* :class:`Symfony\\Component\\JsonPath\\Exception\\JsonCrawlerException`: + Thrown for errors within the JsonPath expression itself, such as using an unknown function -* :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidArgumentException`: Thrown if the input to the ``JsonCrawler`` constructor is not a valid JSON string. -* :class:`Symfony\\Component\\JsonPath\\Exception\\InvalidJsonStringInputException`: Thrown during a ``find()`` call if the JSON string is malformed (e.g., syntax error). -* :class:`Symfony\\Component\\JsonPath\\Exception\\JsonCrawlerException`: Thrown for errors within the JsonPath expression itself, such as using an unknown function:: +Example of handling errors:: use Symfony\Component\JsonPath\Exception\InvalidJsonStringInputException; use Symfony\Component\JsonPath\Exception\JsonCrawlerException; try { - // Example of malformed JSON + // the following line contains malformed JSON $crawler = new JsonCrawler('{"store": }'); $crawler->find('$..*'); } catch (InvalidJsonStringInputException $e) { @@ -234,10 +239,10 @@ The component will throw specific exceptions for invalid input or queries: } try { - // Example of an invalid query + // the following line contains an invalid query $crawler->find('$.store.book[?unknown_function(@.price)]'); } catch (JsonCrawlerException $e) { // ... handle error } -.. _`RFC 9535 - JSONPath`: https://datatracker.ietf.org/doc/html/rfc9535 +.. _`RFC 9535 – JSONPath`: https://datatracker.ietf.org/doc/html/rfc9535