CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-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.

Pending
Overview
Eval results
Files

core-parsing.mddocs/

Core Parsing and Expression Building

Parse JSONPath expressions from strings or build them programmatically using AST classes. JSONPath-NG provides a full parser for standard JSONPath syntax and supports programmatic construction for complex use cases.

Capabilities

String Parsing

Parse JSONPath expressions from strings into executable JSONPath objects.

def parse(string: str) -> JSONPath:
    """
    Parse a JSONPath string expression into a JSONPath object.
    
    Args:
        string: JSONPath expression string (e.g., '$.foo[*].bar')
        
    Returns:
        JSONPath object that can be used for find/update/filter operations
        
    Raises:
        JsonPathParserError: If the string contains invalid JSONPath syntax
    """

Usage example:

from jsonpath_ng import parse

# Simple field access
expr = parse('$.users[*].name')

# Complex nested paths
expr = parse('$.store.book[0].author')

# Wildcards and slicing
expr = parse('$.products[*].reviews[1:3]')

# Union expressions
expr = parse('$.users[*].(name|email)')

Root Expression

Reference to the root object in JSON data structure.

class Root(JSONPath):
    """JSONPath referring to the root object. Concrete syntax is '$'."""
    
    def find(self, data) -> List[DatumInContext]:
        """Find root object, returns single-element list containing root data"""
        
    def update(self, data, val):
        """Replace entire root object with val"""
        
    def filter(self, fn, data):
        """Apply filter function to root data"""

This Expression

Reference to the current object in JSONPath context.

class This(JSONPath):
    """JSONPath referring to current datum. Concrete syntax is '@' or '`this`'."""
    
    def find(self, datum) -> List[DatumInContext]:
        """Find current datum, returns single-element list"""
        
    def update(self, data, val):
        """Replace current data with val"""
        
    def filter(self, fn, data):
        """Apply filter function to current data"""

Field Access

Access object fields by name, including wildcards and multi-field selection.

class Fields(JSONPath):
    """JSONPath referring to object fields. Supports wildcards and multiple fields."""
    
    def __init__(self, *fields: str):
        """
        Initialize field accessor.
        
        Args:
            *fields: Field names to access. Use '*' for all fields.
        """
        
    def find(self, datum) -> List[DatumInContext]:
        """Find values for specified fields"""
        
    def find_or_create(self, datum) -> List[DatumInContext]:
        """Find values, creating empty objects for missing fields"""
        
    def update(self, data, val):
        """Update specified fields with val"""
        
    def update_or_create(self, data, val):
        """Update fields, creating them if they don't exist"""
        
    def filter(self, fn, data):
        """Remove fields where filter function returns True"""
        
    def reified_fields(self, datum) -> Tuple[str, ...]:
        """Get actual field names, expanding wildcards"""
        
    @staticmethod
    def get_field_datum(datum, field: str, create: bool) -> Optional[DatumInContext]:
        """Get datum for specific field, optionally creating if missing"""

Array Indexing

Access array elements by numeric index.

class Index(JSONPath):
    """JSONPath for array indices. Concrete syntax is '[n]'."""
    
    def __init__(self, index: int):
        """
        Initialize index accessor.
        
        Args:
            index: Array index (0-based, negative indices supported)
        """
        
    def find(self, datum) -> List[DatumInContext]:
        """Find element at specified index"""
        
    def find_or_create(self, datum) -> List[DatumInContext]:
        """Find element, padding array if index is beyond current length"""
        
    def update(self, data, val):
        """Update element at specified index"""
        
    def update_or_create(self, data, val):
        """Update element, expanding array if necessary"""
        
    def filter(self, fn, data):
        """Remove element if filter function returns True"""

Array Slicing

Access array slices using Python-style slice notation.

class Slice(JSONPath):
    """JSONPath for array slices. Supports '[start:end:step]' and '[*]' syntax."""
    
    def __init__(self, start: Optional[int] = None, end: Optional[int] = None, step: Optional[int] = None):
        """
        Initialize slice accessor.
        
        Args:
            start: Start index (inclusive)
            end: End index (exclusive)  
            step: Step size
        """
        
    def find(self, datum) -> List[DatumInContext]:
        """Find elements in slice range"""
        
    def update(self, data, val):
        """Update all elements in slice range"""
        
    def filter(self, fn, data):
        """Remove elements in slice where filter function returns True"""

Expression Composition

Combine JSONPath expressions using composition operators.

class Child(JSONPath):
    """JSONPath combining left and right expressions. Concrete syntax is 'left.right'."""
    
    def __init__(self, left: JSONPath, right: JSONPath):
        """
        Initialize child expression.
        
        Args:
            left: Parent JSONPath expression
            right: Child JSONPath expression
        """
        
    def find(self, datum) -> List[DatumInContext]:
        """Find right expression results starting from left expression matches"""
        
    def find_or_create(self, datum) -> List[DatumInContext]:
        """Find with creation of missing intermediate objects"""
        
    def update(self, data, val):
        """Update right expression targets within left expression matches"""
        
    def update_or_create(self, data, val):
        """Update with creation of missing intermediate objects"""
        
    def filter(self, fn, data):
        """Apply filter to right expression targets within left expression matches"""

class Union(JSONPath):
    """JSONPath union of results. Concrete syntax is 'left|right'."""
    
    def __init__(self, left: JSONPath, right: JSONPath):
        """
        Initialize union expression.
        
        Args:
            left: First JSONPath expression
            right: Second JSONPath expression
        """
        
    def find(self, data) -> List[DatumInContext]:
        """Find union of left and right expression results"""
        
    def is_singular(self) -> bool:
        """Always returns False as unions produce multiple results"""

class Descendants(JSONPath):
    """JSONPath recursive descendant matching. Concrete syntax is 'left..right'."""
    
    def __init__(self, left: JSONPath, right: JSONPath):
        """
        Initialize descendants expression.
        
        Args:
            left: Ancestor JSONPath expression
            right: Descendant JSONPath expression to match
        """
        
    def find(self, datum) -> List[DatumInContext]:
        """Find right expression matches recursively within left expression results"""
        
    def update(self, data, val):
        """Update all descendant matches"""
        
    def filter(self, fn, data):
        """Filter all descendant matches"""
        
    def is_singular(self) -> bool:
        """Always returns False as descendants produce multiple results"""

Conditional Expressions

Filter expressions based on conditions.

class Where(JSONPath):
    """JSONPath filtering based on condition. Concrete syntax is 'left where right'."""
    
    def __init__(self, left: JSONPath, right: JSONPath):
        """
        Initialize where expression.
        
        Args:
            left: Base JSONPath expression
            right: Condition JSONPath expression
        """
        
    def find(self, data) -> List[DatumInContext]:
        """Find left expression results that have matches for right expression"""
        
    def update(self, data, val):
        """Update matching left expression results"""
        
    def filter(self, fn, data):
        """Apply filter to matching left expression results"""

class WhereNot(Where):
    """JSONPath filtering based on negated condition. Concrete syntax is 'left wherenot right'."""
    
    def find(self, data) -> List[DatumInContext]:
        """Find left expression results that do NOT have matches for right expression"""

Special Expressions

Additional expression types for advanced use cases.

class Parent(JSONPath):
    """JSONPath matching parent node. Available via named operator '`parent`'."""
    
    def find(self, datum) -> List[DatumInContext]:
        """Find parent of current datum"""

class Intersect(JSONPath):
    """JSONPath intersection (not implemented). Concrete syntax is 'left&right'."""
    
    def __init__(self, left: JSONPath, right: JSONPath):
        """Initialize intersection expression (not implemented)"""
        
    def find(self, data) -> List[DatumInContext]:
        """Not implemented - raises NotImplementedError"""
        
    def is_singular(self) -> bool:
        """Always returns False"""

Programmatic Construction

Build JSONPath expressions programmatically without parsing strings:

from jsonpath_ng.jsonpath import Root, Fields, Index, Child, Slice

# Equivalent to '$.foo[*].bar'
expr = Root().child(Fields('foo')).child(Slice()).child(Fields('bar'))

# Equivalent to '$.users[0].profile.name'  
expr = Child(
    Child(
        Child(Root(), Fields('users')),
        Index(0)
    ),
    Child(Fields('profile'), Fields('name'))
)

# Using the convenience child() method
expr = Root().child(Fields('users')).child(Index(0)).child(Fields('profile')).child(Fields('name'))

Parser and Lexer Configuration

class JsonPathParser:
    """LALR parser for JSONPath expressions."""
    
    def __init__(self, debug: bool = False, lexer_class=None):
        """
        Initialize parser.
        
        Args:
            debug: Enable debug output
            lexer_class: Custom lexer class (defaults to JsonPathLexer)
        """
        
    def parse(self, string: str, lexer=None) -> JSONPath:
        """Parse JSONPath string into JSONPath object"""
        
    def parse_token_stream(self, token_iterator) -> JSONPath:
        """Parse from token iterator"""

class JsonPathLexer:
    """Lexical analyzer for JSONPath expressions."""
    
    def __init__(self, debug: bool = False):
        """
        Initialize lexer.
        
        Args:
            debug: Enable debug output
        """
        
    def tokenize(self, string: str) -> Iterator[Token]:
        """
        Tokenize JSONPath string.
        
        Args:
            string: JSONPath expression string
            
        Returns:
            Iterator of tokens for parsing
        """
    
    # Class attributes
    literals: List[str]  # List of literal characters
    reserved_words: Dict[str, str]  # Reserved word mappings
    tokens: List[str]  # List of token types

Exceptions

class JSONPathError(Exception):
    """Base exception for JSONPath operations"""

class JsonPathParserError(JSONPathError):
    """Parser-specific exceptions for invalid JSONPath syntax"""

class JsonPathLexerError(JSONPathError):
    """Lexer-specific exceptions for invalid tokens"""

Install with Tessl CLI

npx tessl i tessl/pypi-jsonpath-ng

docs

command-line.md

core-parsing.md

extensions.md

index.md

path-operations.md

tile.json