Quick Start

This page gets you started using JSONPath with Python. See JSONPath Syntax for an introduction to JSONPath expression syntax.

Find nodes

jsonpath_rfc9535.find() applies a JSONPath expression to JSON-like data and returns a list of nodes - one instance of jsonpath_rfc9535.JSONPathNode for each matched value.

A node contains both the matched value and its location in the argument data, plus methods for serializing locations to normalized paths and retrieving parent nodes.

import jsonpath_rfc9535 as jsonpath

expr = "$.users[?@.status == 'pending'].name"

data: dict[str, object] = {
    "users": [
        {"id": "usr_101", "name": "Alice", "status": "pending"},
        {"id": "usr_102", "name": "Bob", "status": "active"},
        {"id": "usr_103", "name": "Charlie", "status": "pending"},
    ],
}

for node in jsonpath.find(expr, data):
    print(node.path(), "->", node.value)

# $['users'][0]['name'] -> Alice
# $['users'][2]['name'] -> Charlie

find() returns a list subclass, jsonpath_rfc9535.JSONPathNodeList, with methods for retrieving all values, locations or normalized paths for the entire list of nodes.

# ... continued from above

nodes = jsonpath.find(expr, data)

print(nodes.values())  # ['Alice', 'Charlie']
print(nodes.locations())  # [('users', 0, 'name'), ('users', 2, 'name')]
print(nodes.paths())  # ["$['users'][0]['name']", "$['users'][2]['name']"]

Find values

Use jsonpath_rfc9535.findall() instead of find() if you’re interested in matched values only, without location and parent node information.

findall() can be significantly faster and more memory efficient than find().

import jsonpath_rfc9535 as jsonpath

expr = "$.users[?@.status == 'pending'].name"

data: dict[str, object] = {
    "users": [
        {"id": "usr_101", "name": "Alice", "status": "pending"},
        {"id": "usr_102", "name": "Bob", "status": "active"},
        {"id": "usr_103", "name": "Charlie", "status": "pending"},
    ],
}

values = jsonpath.findall(expr, data)
print(values)  # ['Alice', 'Charlie']

Node generator

jsonpath_rfc9535.finditer() yields instances of jsonpath_rfc9535.JSONPathNode instead of materializing all nodes into a node list.

import jsonpath_rfc9535 as jsonpath

expr = "$.users[?@.status == 'pending'].name"

data: dict[str, object] = {
    "users": [
        {"id": "usr_101", "name": "Alice", "status": "pending"},
        {"id": "usr_102", "name": "Bob", "status": "active"},
        {"id": "usr_103", "name": "Charlie", "status": "pending"},
    ],
}

for node in jsonpath.finditer(expr, data):
    print(node.value)

Just the first node

jsonpath_rfc9535.search() applies a JSONPath expression to JSON-like data and returns the first node found, or None if there were no matches.

import jsonpath_rfc9535 as jsonpath

expr = "$.users[?@.status == 'pending'].name"

data: dict[str, object] = {
    "users": [
        {"id": "usr_101", "name": "Alice", "status": "pending"},
        {"id": "usr_102", "name": "Bob", "status": "active"},
        {"id": "usr_103", "name": "Charlie", "status": "pending"},
    ],
}

node = jsonpath.search(expr, data)
print(node.value)  # Alice

search() is equivalent to:

# ... continued from above

try:
    node = next(iter(jsonpath.finditer(expr, data)))
except StopIteration:
    node = None

You could easily take, say, the first 5 nodes using islice().

# ... continued from above

it = islice(jsonpath.finditer(expr, data), 5)

Compilation

Use jsonpath_rfc9535.compile() to parse a JSONPath expression for later evaluation, potentially against different data.

compile() returns an instance of jsonpath_rfc9535.JSONPathQuery with find(), findall(), finditer() and search() methods equivalent to the package level functions described above.

import jsonpath_rfc9535 as jsonpath

query = jsonpath.compile("$.users[?@.status == 'pending'].name")

data: dict[str, object] = {
    "users": [
        {"id": "usr_101", "name": "Alice", "status": "pending"},
        {"id": "usr_102", "name": "Bob", "status": "active"},
        {"id": "usr_103", "name": "Charlie", "status": "pending"},
    ],
}

nodes = query.find(data)
# ...

We don’t cache parsed queries between calls to find(), finditer(), etc. So it is well worth compiling your JSONPath expressions up front.

Configuration

Package level functions find(), findall(), finditer(), search() and compile() are convenience functions that use the default JSONPath environment. We can configure JSONPath by creating our own instance of jsonpath_rfc9535.JSONPathEnvironment and using its find(), findall(), finditer(), search() and compile() methods.

The arguments given in this example match the defaults.

from jsonpath_rfc9535 import JSONPathEnvironment, StandardParser

env = JSONPathEnvironment(
    max_index=(2**53) - 1,
    min_index=-(2**53) + 1,
    max_recursion_depth=100,
    max_expression_depth=30,
    parser=StandardParser,
)

nodes = env.find("$.some.thing")
# ...

An instance of JSONPathEnvironment is also where you’d register custom Function Extensions.

Exceptions

find(), findall(), finditer(), search() and compile() functions and methods can raise exceptions at JSONPath expression compile time and/or query evaluation time.

All of the following exceptions inherit from jsonpath_rfc9535.JSONPathError.

Compile time exceptions

  • JSONPathSyntaxError

  • JSONPathNameError (unknown filter function)

  • JSONPathTypeError

  • JSONPathIndexError

  • JSONPathRecursionError if a maximum expression depth is set.

Evaluation time exceptions

  • JSONPathRecursionError if a descendant segment recursion limit is set.

  • JSONPathError when debugging regex filters.