jsonpath-ng
A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming.
Downloads: 0 (30 days)
Description
Python JSONPath Next-Generation |Build Status| |PyPI|
=====================================================
A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic
and binary comparison operators, as defined in the original `JSONPath proposal`_.
This packages merges both `jsonpath-rw`_ and `jsonpath-rw-ext`_ and
provides several AST API enhancements, such as the ability to update or remove nodes in the tree.
About
-----
This library provides a robust and significantly extended implementation
of JSONPath for Python. It is tested with CPython 3.10 and higher.
This library differs from other JSONPath implementations in that it is a
full *language* implementation, meaning the JSONPath expressions are
first class objects, easy to analyze, transform, parse, print, and
extend.
Quick Start
-----------
To install, use pip:
.. code:: bash
$ pip install --upgrade jsonpath-ng
Usage
-----
Basic examples:
.. code:: python
$ python
>>> from jsonpath_ng import jsonpath, parse
# A robust parser, not just a regex. (Makes powerful extensions possible; see below)
>>> jsonpath_expr = parse('foo[*].baz')
# Extracting values is easy
>>> [match.value for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
[1, 2]
# Matches remember where they came from
>>> [str(match.full_path) for match in jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})]
['foo.[0].baz', 'foo.[1].baz']
# Modifying values matching the path
>>> jsonpath_expr.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
{'foo': [{'baz': 3}, {'baz': 3}]}
# Modifying one of the values matching the path
>>> matches = jsonpath_expr.find({'foo': [{'baz': 1}, {'baz': 2}]})
>>> matches[0].full_path.update( {'foo': [{'baz': 1}, {'baz': 2}]}, 3)
{'foo': [{'baz': 3}, {'baz': 2}]}
# Removing all values matching a path
>>> jsonpath_expr.filter(lambda d: True, {'foo': [{'baz': 1}, {'baz': 2}]})
{'foo': [{}, {}]}
# Removing values containing particular data matching path
>>> jsonpath_expr.filter(lambda d: d == 2, {'foo': [{'baz': 1}, {'baz': 2}]})
{'foo': [{'baz': 1}, {}]}
# And this can be useful for automatically providing ids for bits of data that do not have them (currently a global switch)
>>> jsonpath.auto_id_field = 'id'
>>> [match.value for match in parse('foo[*].id').find({'foo': [{'id': 'bizzle'}, {'baz': 3}]})]
['foo.bizzle', 'foo.[1]']
# A handy extension: named operators like `parent`
>>> [match.value for match in parse('a.*.b.`parent`.c').find({'a': {'x': {'b': 1, 'c': 'number one'}, 'y': {'b': 2, 'c': 'number two'}}})]
['number two', 'number one']
# You can also build expressions directly quite easily
>>> from jsonpath_ng.jsonpath import Fields
>>> from jsonpath_ng.jsonpath import Slice
>>> jsonpath_expr_direct = Fields('foo').child(Slice('*')).child(Fields('baz')) # This is equivalent
Using the extended parser:
.. code:: python
$ python
>>> from jsonpath_ng.ext import parse
# A robust parser, not just a regex. (Makes powerful extensions possible; see below)
>>> jsonpath_expr = parse('foo[*].baz')
JSONPath Syntax
---------------
The JSONPath syntax supported by this library includes some additional
features and omits some problematic features (those that make it
unportable). In particular, some new operators such as ``|`` and
``where`` are available, and parentheses are used for grouping not for
callbacks into Python, since with these changes the language is not
trivially associative. Also, fields may be quoted whether or not they
are contained in brackets.
Atomic expressions:
+-----------------------+---------------------------------------------------------------------------------------------+
| Syntax | Meaning |
+=======================+=============================================================================================+
| ``$`` | The root object |
+-----------------------+---------------------------------------------------------------------------------------------+
| ```this``` | The "current" object. |
+-----------------------+---------------------------------------------------------------------------------------------+
| ```foo``` | More generally, this syntax allows "named operators" to extend JSONPath is arbitrary ways |
+-----------------------+---------------------------------------------------------------------------------------------+
| *field* | Specified field(s), described below |
+-----------------------+---------------------------------------------------------------------------------------------+
| ``[`` *field* ``]`` | Same as *field* |
+-----------------------+---------------------------------------------------------------------------------------------+
| ``[`` *idx* ``]`` | Array access, described below (this is always unambiguous with field access) |
+-----------------------+---------------------------------------------------------------------------------------------+
Jsonpath operators:
+--------------------------------------+-----------------------------------------------------------------------------------+
| Syntax | Meaning |
+======================================+===================================================================================+
| *jsonpath1* ``.`` *jsonpath2* | All nodes matched by *jsonpath2* starting at any node matching *jsonpath1* |
+--------------------------------------+-----------------------------------------------------------------------------------+
| *jsonpath* ``[`` *whatever* ``]`` | Same as *jsonpath*\ ``.``\ *whatever* |
+--------------------------------------+-----------------------------------------------------------------------------------+
| *jsonpath1* ``..`` *jsonpath2* | All nodes matched by *jsonpath2* that descend from any node matching *jsonpath1* |
+--------------------------------------+-----------------------------------------------------------------------------------+
| *jsonpath1* ``where`` *jsonpath2* | Any nodes matching *jsonpath1* with a child matching *jsonpath2* |
+--------------------------------------+-----------------------------------------------------------------------------------+
| *jsonpath1* ``wherenot`` *jsonpath2* | Any nodes matching *jsonpath1* with a child not matching *jsonpath2* |
+--------------------------------------+-----------------------------------------------------------------------------------+
| *jsonpath1* ``|`` *jsonpath2* | Any nodes matching the union of *jsonpath1* and *jsonpath2* |
+--------------------------------------+-----------------------------------------------------------------------------------+
Field specifiers ( *field* ):
+-------------------------+-------------------------------------------------------------------------------------+
| Syntax | Meaning |
+=========================+=====================================================================================+
| ``fieldname`` | the field ``fieldname`` (from the "current" object) |
+-------------------------+-------------------------------------------------------------------------------------+
| ``"fieldname"`` | same as above, for allowing special characters in the fieldname |
+-------------------------+-------------------------------------------------------------------------------------+
| ``'fieldname'`` | ditto |
+-------------------------+-------------------------------------------------------------------------------------+
| ``*`` | any field |
+-------------------------+-------------------------------------------------------------------------------------+
| *field* ``,`` *field* | either of the named fields (you can always build equivalent jsonpath using ``|``) |
+-------------------------+-------------------------------------------------------------------------------------+
Array specifiers ( *idx* ):
+-----------------------------------------+---------------------------------------------------------------------------------------+
| Syntax | Meaning |
+=========================================+=======================================================================================+
| ``[``\ *n*\ ``]`` | array index (may be comma-separated list) |
+-----------------------------------------+---------------------------------------------------------------------------------------+
| ``[``\ *start*\ ``?:``\ *end*\ ``?]`` | array slicing (note that *step* is unimplemented only due to lack of need thus far) |
+-----------------------------------------+---------------------------------------------------------------------------------------+
| ``[*]`` | any array index