A robust and significantly extended implementation of JSONPath for Python, with a clear AST for metaprogramming.
—
Core Abstract Syntax Tree (AST) classes representing different JSONPath operations. These classes form the building blocks of parsed JSONPath expressions and can be used to construct expressions programmatically.
Abstract base class defining the interface for all JSONPath expression types.
class JSONPath:
"""
Base class for JSONPath abstract syntax tree nodes.
"""
def find(self, data):
"""
Find all matches for this JSONPath in the given data.
Parameters:
- data: Input data to search (dict, list, or DatumInContext)
Returns:
list[DatumInContext]: List of matching data with context
"""
def update(self, data, val):
"""
Update data at the path specified by this JSONPath.
Parameters:
- data: Input data to update
- val: New value to set at the path
Returns:
Updated data structure
"""
def child(self, child):
"""
Create a child path with canonicalization.
Parameters:
- child: JSONPath object to use as child
Returns:
JSONPath: Composed path expression
"""
def make_datum(self, value):
"""
Create a DatumInContext from a value.
Parameters:
- value: Value to wrap (or existing DatumInContext)
Returns:
DatumInContext: Wrapped value with path context
"""Represents the root object reference ($ in JSONPath syntax).
class Root(JSONPath):
"""
JSONPath referring to the root object. Concrete syntax: '$'
"""
def find(self, data):
"""
Returns the root datum.
Parameters:
- data: Input data
Returns:
list[DatumInContext]: Single-element list with root datum
"""
def update(self, data, val):
"""
Replace entire data with new value.
Parameters:
- data: Original data
- val: Replacement value
Returns:
val: The replacement value
"""Represents the current datum reference (@ or `this` in JSONPath syntax).
class This(JSONPath):
"""
JSONPath referring to the current datum. Concrete syntax: '@' or `this`
"""
def find(self, datum):
"""
Returns the current datum wrapped in context.
Parameters:
- datum: Current datum
Returns:
list[DatumInContext]: Single-element list with wrapped datum
"""
def update(self, data, val):
"""
Replace data with new value.
Parameters:
- data: Original data
- val: Replacement value
Returns:
val: The replacement value
"""Represents field access operations for objects.
class Fields(JSONPath):
"""
JSONPath for field access. Supports single fields, multiple fields, and wildcards.
"""
def __init__(self, *fields):
"""
Initialize field access expression.
Parameters:
- fields: Variable number of field names (str)
Use '*' for all fields
"""
def find(self, datum):
"""
Find matching fields in the datum.
Parameters:
- datum: Input datum (typically dict-like)
Returns:
list[DatumInContext]: Matching field values with context
"""
def get_field_datum(self, datum, field):
"""
Get a specific field from datum.
Parameters:
- datum: DatumInContext containing dict-like value
- field: str, field name to access
Returns:
DatumInContext or None: Field value with context, or None if not found
"""
def reified_fields(self, datum):
"""
Expand '*' wildcards to actual field names.
Parameters:
- datum: DatumInContext containing dict-like value
Returns:
tuple: Actual field names to access
"""
def update(self, data, val):
"""
Update data by setting field values.
Parameters:
- data: Input data structure
- val: New value to set at field paths
Returns:
Updated data structure with field values set
"""Represents array index access operations.
class Index(JSONPath):
"""
JSONPath for array index access. Concrete syntax: [n]
"""
def __init__(self, index):
"""
Initialize index access expression.
Parameters:
- index: int, array index to access
"""
def find(self, datum):
"""
Find element at the specified index.
Parameters:
- datum: Input datum (typically list-like)
Returns:
list[DatumInContext]: Single element if index exists, empty list otherwise
"""
def update(self, data, val):
"""
Update data by setting value at the specified index.
Parameters:
- data: Input data structure (typically list-like)
- val: New value to set at the index
Returns:
Updated data structure with value set at index
"""Represents array slice operations with optional start, end, and step parameters.
class Slice(JSONPath):
"""
JSONPath for array slice access. Concrete syntax: [start:end:step] or [*]
Includes type coercion for non-array data.
"""
def __init__(self, start=None, end=None, step=None):
"""
Initialize slice expression.
Parameters:
- start: int or None, slice start index
- end: int or None, slice end index
- step: int or None, slice step size
Note: If all parameters are None, acts as wildcard [*]
"""
def find(self, datum):
"""
Find elements in the specified slice.
Coerces non-list data to single-element lists.
Parameters:
- datum: Input datum
Returns:
list[DatumInContext]: Slice elements with context
"""
def update(self, data, val):
"""
Update data by setting values in the specified slice.
Parameters:
- data: Input data structure
- val: New value to set in slice positions
Returns:
Updated data structure with slice values set
"""Represents path composition operations (left.right).
class Child(JSONPath):
"""
JSONPath that first matches the left, then the right.
Concrete syntax: <left>.<right>
"""
def __init__(self, left, right):
"""
Initialize child composition.
Parameters:
- left: JSONPath, first expression to match
- right: JSONPath, second expression to match from left results
"""
def find(self, datum):
"""
Find right matches from all left matches.
Parameters:
- datum: Input datum
Returns:
list[DatumInContext]: All right matches from left results
"""Represents parent node access (`parent` named operator).
class Parent(JSONPath):
"""
JSONPath that matches the parent node of the current match.
Available via named operator `parent`.
"""
def find(self, datum):
"""
Find the parent context of the datum.
Parameters:
- datum: DatumInContext with parent context
Returns:
list[DatumInContext]: Parent context
Note: Will crash if no parent exists
"""Represents descendant access operations (left..right).
class Descendants(JSONPath):
"""
JSONPath that matches descendants. Concrete syntax: <left>..<right>
Finds all nodes matching right that descend from left matches.
"""
def __init__(self, left, right):
"""
Initialize descendant query.
Parameters:
- left: JSONPath, ancestor expression
- right: JSONPath, descendant expression to match
"""
def find(self, datum):
"""
Find all right matches that descend from left matches.
Recursively searches through objects and arrays.
Parameters:
- datum: Input datum
Returns:
list[DatumInContext]: All descendant matches
"""
def is_singular(self):
"""
Check if this expression returns a single result.
Returns:
bool: Always False for descendant expressions
"""Represents filtering operations (left where right).
class Where(JSONPath):
"""
JSONPath for filtering. Concrete syntax: <left> where <right>
Filters left matches to only those that have right matches.
"""
def __init__(self, left, right):
"""
Initialize filter expression.
Parameters:
- left: JSONPath, expression to filter
- right: JSONPath, filter condition expression
"""
def find(self, data):
"""
Filter left matches that have right matches.
Parameters:
- data: Input data
Returns:
list[DatumInContext]: Filtered left matches
"""Represents union operations (left|right).
class Union(JSONPath):
"""
JSONPath that returns union of results. Concrete syntax: <left>|<right>
"""
def __init__(self, left, right):
"""
Initialize union expression.
Parameters:
- left: JSONPath, first expression
- right: JSONPath, second expression
"""
def find(self, data):
"""
Return combined results from both expressions.
Parameters:
- data: Input data
Returns:
list[DatumInContext]: Combined results from left and right
"""
def is_singular(self):
"""
Check if this expression returns a single result.
Returns:
bool: Always False for union expressions
"""Placeholder for intersection operations (left&right).
class Intersect(JSONPath):
"""
JSONPath for intersection. Concrete syntax: <left>&<right>
WARNING: Not implemented - find() raises NotImplementedError
"""
def __init__(self, left, right):
"""
Initialize intersection expression.
Parameters:
- left: JSONPath, first expression
- right: JSONPath, second expression
"""
def find(self, data):
"""
Find intersection of left and right matches.
Parameters:
- data: Input data
Raises:
NotImplementedError: Intersection is not yet implemented
"""
def is_singular(self):
"""
Check if this expression returns a single result.
Returns:
bool: Always False for intersection expressions
"""You can build JSONPath expressions directly without parsing:
from jsonpath_rw.jsonpath import Root, Fields, Slice, Index
# Equivalent to parse('$.foo[*].bar')
expr = Root().child(Fields('foo')).child(Slice()).child(Fields('bar'))
# Equivalent to parse('users[0].name')
expr = Fields('users').child(Index(0)).child(Fields('name'))
# Multiple fields: parse('name,email,age')
expr = Fields('name', 'email', 'age')Install with Tessl CLI
npx tessl i tessl/pypi-jsonpath-rw