jsonpath-rfc9535

RFC 9535 - JSONPath: Query Expressions for JSON in Python


Keywords
json, jsonpath, jsonpath-library, jsonpath-parser, jsonpath-query, jsonpath-syntax, python, python3
License
MIT
Install
pip install jsonpath-rfc9535==0.1.2

Documentation

RFC 9535 JSONPath: Query Expressions for JSON in Python

We follow RFC 9535 strictly and test against the JSONPath Compliance Test Suite.

License Tests
PyPi - Version Python versions


Table of Contents

Install

Install Python JSONPath RFC 9535 using pip:

pip install jsonpath-rfc9535

Or Pipenv:

pipenv install -u jsonpath-rfc9535

Example

import jsonpath_rfc9535 as jsonpath

data = {
    "users": [
        {"name": "Sue", "score": 100},
        {"name": "Sally", "score": 84, "admin": False},
        {"name": "John", "score": 86, "admin": True},
        {"name": "Jane", "score": 55},
    ],
    "moderator": "John",
}

for node in jsonpath.find("$.users[?@.score > 85]", data):
    print(node.value)

# {'name': 'Sue', 'score': 100}
# {'name': 'John', 'score': 86, 'admin': True}

Or, reading JSON data from a file:

import json
import jsonpath_rfc9535 as jsonpath

with open("/path/to/some.json", encoding="utf-8") as fd:
    data = json.load(fd)

nodes = jsonpath.find("$.some.query", data)
values = nodes.values()
# ...

You could read data from a YAML formatted file too. If you have PyYaml installed:

import jsonpath_rfc9535 as jsonpath
import yaml

with open("some.yaml") as fd:
    data = yaml.safe_load(fd)

products = jsonpath.find("$..products.*", data).values()
# ...

Links

Related projects

  • Python JSONPath - Another Python package implementing JSONPath, but with additional features and customization options.
  • JSON P3 - RFC 9535 implemented in TypeScript.

API

find

find(query: str, value: JSONValue) -> JSONPathNodeList

Apply JSONPath expression query to value. value should arbitrary, possible nested, Python dictionaries, lists, strings, integers, floats, Booleans or None, as you would get from json.load().

A list of JSONPathNode instances is returned, one node for each value matched by path. The returned list will be empty if there were no matches.

Each JSONPathNode has:

  • a value property, which is the JSON-like value associated with the node.
  • a location property, which is a tuple of property names and array/list indexes that were required to reach the node's value in the target JSON document.
  • a path() method, which returns the normalized path to the node in the target JSON document.
import jsonpath_rfc9535 as jsonpath

value = {
    "users": [
        {"name": "Sue", "score": 100},
        {"name": "John", "score": 86, "admin": True},
        {"name": "Sally", "score": 84, "admin": False},
        {"name": "Jane", "score": 55},
    ],
    "moderator": "John",
}

for node in jsonpath.find("$.users[?@.score > 85]", value):
    print(f"{node.value} at '{node.path()}'")

# {'name': 'Sue', 'score': 100} at '$['users'][0]'
# {'name': 'John', 'score': 86, 'admin': True} at '$['users'][1]'

JSONPathNodeList is a subclass of list with some helper methods.

  • values() returns a list of values, one for each node.
  • items() returns a list of (normalized path, value) tuples.

find_one

find_one(query: str, value: JSONValue) -> Optional[JSONPathNode]

find_one() accepts the same arguments as find(), but returns the first available JSONPathNode, or None if there were no matches.

find_one() is equivalent to:

def find_one(query, value):
    try:
        return next(iter(jsonpath.finditer(query, value)))
    except StopIteration:
        return None

finditer

finditer(query: str, value: JSONValue) -> Iterable[JSONPathNode]

finditer() accepts the same arguments as find(), but returns an iterator over JSONPathNode instances rather than a list. This could be useful if you're expecting a large number of results that you don't want to load into memory all at once.

compile

compile(query: str) -> JSONPathQuery

find(query, value) is a convenience function for JSONPathEnvironment().compile(query).apply(value). Use compile(query) to obtain a JSONPathQuery instance which can be applied to difference JSON-like values repeatedly.

import jsonpath_rfc9535 as jsonpath

value = {
    "users": [
        {"name": "Sue", "score": 100},
        {"name": "John", "score": 86, "admin": True},
        {"name": "Sally", "score": 84, "admin": False},
        {"name": "Jane", "score": 55},
    ],
    "moderator": "John",
}

query = jsonpath.compile("$.users[?@.score > 85]")

for node in query.apply(value):
    print(f"{node.value} at '{node.path()}'")

# {'name': 'Sue', 'score': 100} at '$['users'][0]'
# {'name': 'John', 'score': 86, 'admin': True} at '$['users'][1]'

A JSONPathQuery has a finditer(value) method too, and find(value) is an alias for apply(value).

License

python-jsonpath-rfc9535 is distributed under the terms of the MIT license.