0
# Core Parsing and Expression Building
1
2
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.
3
4
## Capabilities
5
6
### String Parsing
7
8
Parse JSONPath expressions from strings into executable JSONPath objects.
9
10
```python { .api }
11
def parse(string: str) -> JSONPath:
12
"""
13
Parse a JSONPath string expression into a JSONPath object.
14
15
Args:
16
string: JSONPath expression string (e.g., '$.foo[*].bar')
17
18
Returns:
19
JSONPath object that can be used for find/update/filter operations
20
21
Raises:
22
JsonPathParserError: If the string contains invalid JSONPath syntax
23
"""
24
```
25
26
Usage example:
27
28
```python
29
from jsonpath_ng import parse
30
31
# Simple field access
32
expr = parse('$.users[*].name')
33
34
# Complex nested paths
35
expr = parse('$.store.book[0].author')
36
37
# Wildcards and slicing
38
expr = parse('$.products[*].reviews[1:3]')
39
40
# Union expressions
41
expr = parse('$.users[*].(name|email)')
42
```
43
44
### Root Expression
45
46
Reference to the root object in JSON data structure.
47
48
```python { .api }
49
class Root(JSONPath):
50
"""JSONPath referring to the root object. Concrete syntax is '$'."""
51
52
def find(self, data) -> List[DatumInContext]:
53
"""Find root object, returns single-element list containing root data"""
54
55
def update(self, data, val):
56
"""Replace entire root object with val"""
57
58
def filter(self, fn, data):
59
"""Apply filter function to root data"""
60
```
61
62
### This Expression
63
64
Reference to the current object in JSONPath context.
65
66
```python { .api }
67
class This(JSONPath):
68
"""JSONPath referring to current datum. Concrete syntax is '@' or '`this`'."""
69
70
def find(self, datum) -> List[DatumInContext]:
71
"""Find current datum, returns single-element list"""
72
73
def update(self, data, val):
74
"""Replace current data with val"""
75
76
def filter(self, fn, data):
77
"""Apply filter function to current data"""
78
```
79
80
### Field Access
81
82
Access object fields by name, including wildcards and multi-field selection.
83
84
```python { .api }
85
class Fields(JSONPath):
86
"""JSONPath referring to object fields. Supports wildcards and multiple fields."""
87
88
def __init__(self, *fields: str):
89
"""
90
Initialize field accessor.
91
92
Args:
93
*fields: Field names to access. Use '*' for all fields.
94
"""
95
96
def find(self, datum) -> List[DatumInContext]:
97
"""Find values for specified fields"""
98
99
def find_or_create(self, datum) -> List[DatumInContext]:
100
"""Find values, creating empty objects for missing fields"""
101
102
def update(self, data, val):
103
"""Update specified fields with val"""
104
105
def update_or_create(self, data, val):
106
"""Update fields, creating them if they don't exist"""
107
108
def filter(self, fn, data):
109
"""Remove fields where filter function returns True"""
110
111
def reified_fields(self, datum) -> Tuple[str, ...]:
112
"""Get actual field names, expanding wildcards"""
113
114
@staticmethod
115
def get_field_datum(datum, field: str, create: bool) -> Optional[DatumInContext]:
116
"""Get datum for specific field, optionally creating if missing"""
117
```
118
119
### Array Indexing
120
121
Access array elements by numeric index.
122
123
```python { .api }
124
class Index(JSONPath):
125
"""JSONPath for array indices. Concrete syntax is '[n]'."""
126
127
def __init__(self, index: int):
128
"""
129
Initialize index accessor.
130
131
Args:
132
index: Array index (0-based, negative indices supported)
133
"""
134
135
def find(self, datum) -> List[DatumInContext]:
136
"""Find element at specified index"""
137
138
def find_or_create(self, datum) -> List[DatumInContext]:
139
"""Find element, padding array if index is beyond current length"""
140
141
def update(self, data, val):
142
"""Update element at specified index"""
143
144
def update_or_create(self, data, val):
145
"""Update element, expanding array if necessary"""
146
147
def filter(self, fn, data):
148
"""Remove element if filter function returns True"""
149
```
150
151
### Array Slicing
152
153
Access array slices using Python-style slice notation.
154
155
```python { .api }
156
class Slice(JSONPath):
157
"""JSONPath for array slices. Supports '[start:end:step]' and '[*]' syntax."""
158
159
def __init__(self, start: Optional[int] = None, end: Optional[int] = None, step: Optional[int] = None):
160
"""
161
Initialize slice accessor.
162
163
Args:
164
start: Start index (inclusive)
165
end: End index (exclusive)
166
step: Step size
167
"""
168
169
def find(self, datum) -> List[DatumInContext]:
170
"""Find elements in slice range"""
171
172
def update(self, data, val):
173
"""Update all elements in slice range"""
174
175
def filter(self, fn, data):
176
"""Remove elements in slice where filter function returns True"""
177
```
178
179
### Expression Composition
180
181
Combine JSONPath expressions using composition operators.
182
183
```python { .api }
184
class Child(JSONPath):
185
"""JSONPath combining left and right expressions. Concrete syntax is 'left.right'."""
186
187
def __init__(self, left: JSONPath, right: JSONPath):
188
"""
189
Initialize child expression.
190
191
Args:
192
left: Parent JSONPath expression
193
right: Child JSONPath expression
194
"""
195
196
def find(self, datum) -> List[DatumInContext]:
197
"""Find right expression results starting from left expression matches"""
198
199
def find_or_create(self, datum) -> List[DatumInContext]:
200
"""Find with creation of missing intermediate objects"""
201
202
def update(self, data, val):
203
"""Update right expression targets within left expression matches"""
204
205
def update_or_create(self, data, val):
206
"""Update with creation of missing intermediate objects"""
207
208
def filter(self, fn, data):
209
"""Apply filter to right expression targets within left expression matches"""
210
211
class Union(JSONPath):
212
"""JSONPath union of results. Concrete syntax is 'left|right'."""
213
214
def __init__(self, left: JSONPath, right: JSONPath):
215
"""
216
Initialize union expression.
217
218
Args:
219
left: First JSONPath expression
220
right: Second JSONPath expression
221
"""
222
223
def find(self, data) -> List[DatumInContext]:
224
"""Find union of left and right expression results"""
225
226
def is_singular(self) -> bool:
227
"""Always returns False as unions produce multiple results"""
228
229
class Descendants(JSONPath):
230
"""JSONPath recursive descendant matching. Concrete syntax is 'left..right'."""
231
232
def __init__(self, left: JSONPath, right: JSONPath):
233
"""
234
Initialize descendants expression.
235
236
Args:
237
left: Ancestor JSONPath expression
238
right: Descendant JSONPath expression to match
239
"""
240
241
def find(self, datum) -> List[DatumInContext]:
242
"""Find right expression matches recursively within left expression results"""
243
244
def update(self, data, val):
245
"""Update all descendant matches"""
246
247
def filter(self, fn, data):
248
"""Filter all descendant matches"""
249
250
def is_singular(self) -> bool:
251
"""Always returns False as descendants produce multiple results"""
252
```
253
254
### Conditional Expressions
255
256
Filter expressions based on conditions.
257
258
```python { .api }
259
class Where(JSONPath):
260
"""JSONPath filtering based on condition. Concrete syntax is 'left where right'."""
261
262
def __init__(self, left: JSONPath, right: JSONPath):
263
"""
264
Initialize where expression.
265
266
Args:
267
left: Base JSONPath expression
268
right: Condition JSONPath expression
269
"""
270
271
def find(self, data) -> List[DatumInContext]:
272
"""Find left expression results that have matches for right expression"""
273
274
def update(self, data, val):
275
"""Update matching left expression results"""
276
277
def filter(self, fn, data):
278
"""Apply filter to matching left expression results"""
279
280
class WhereNot(Where):
281
"""JSONPath filtering based on negated condition. Concrete syntax is 'left wherenot right'."""
282
283
def find(self, data) -> List[DatumInContext]:
284
"""Find left expression results that do NOT have matches for right expression"""
285
```
286
287
### Special Expressions
288
289
Additional expression types for advanced use cases.
290
291
```python { .api }
292
class Parent(JSONPath):
293
"""JSONPath matching parent node. Available via named operator '`parent`'."""
294
295
def find(self, datum) -> List[DatumInContext]:
296
"""Find parent of current datum"""
297
298
class Intersect(JSONPath):
299
"""JSONPath intersection (not implemented). Concrete syntax is 'left&right'."""
300
301
def __init__(self, left: JSONPath, right: JSONPath):
302
"""Initialize intersection expression (not implemented)"""
303
304
def find(self, data) -> List[DatumInContext]:
305
"""Not implemented - raises NotImplementedError"""
306
307
def is_singular(self) -> bool:
308
"""Always returns False"""
309
```
310
311
## Programmatic Construction
312
313
Build JSONPath expressions programmatically without parsing strings:
314
315
```python
316
from jsonpath_ng.jsonpath import Root, Fields, Index, Child, Slice
317
318
# Equivalent to '$.foo[*].bar'
319
expr = Root().child(Fields('foo')).child(Slice()).child(Fields('bar'))
320
321
# Equivalent to '$.users[0].profile.name'
322
expr = Child(
323
Child(
324
Child(Root(), Fields('users')),
325
Index(0)
326
),
327
Child(Fields('profile'), Fields('name'))
328
)
329
330
# Using the convenience child() method
331
expr = Root().child(Fields('users')).child(Index(0)).child(Fields('profile')).child(Fields('name'))
332
```
333
334
## Parser and Lexer Configuration
335
336
```python { .api }
337
class JsonPathParser:
338
"""LALR parser for JSONPath expressions."""
339
340
def __init__(self, debug: bool = False, lexer_class=None):
341
"""
342
Initialize parser.
343
344
Args:
345
debug: Enable debug output
346
lexer_class: Custom lexer class (defaults to JsonPathLexer)
347
"""
348
349
def parse(self, string: str, lexer=None) -> JSONPath:
350
"""Parse JSONPath string into JSONPath object"""
351
352
def parse_token_stream(self, token_iterator) -> JSONPath:
353
"""Parse from token iterator"""
354
355
class JsonPathLexer:
356
"""Lexical analyzer for JSONPath expressions."""
357
358
def __init__(self, debug: bool = False):
359
"""
360
Initialize lexer.
361
362
Args:
363
debug: Enable debug output
364
"""
365
366
def tokenize(self, string: str) -> Iterator[Token]:
367
"""
368
Tokenize JSONPath string.
369
370
Args:
371
string: JSONPath expression string
372
373
Returns:
374
Iterator of tokens for parsing
375
"""
376
377
# Class attributes
378
literals: List[str] # List of literal characters
379
reserved_words: Dict[str, str] # Reserved word mappings
380
tokens: List[str] # List of token types
381
```
382
383
## Exceptions
384
385
```python { .api }
386
class JSONPathError(Exception):
387
"""Base exception for JSONPath operations"""
388
389
class JsonPathParserError(JSONPathError):
390
"""Parser-specific exceptions for invalid JSONPath syntax"""
391
392
class JsonPathLexerError(JSONPathError):
393
"""Lexer-specific exceptions for invalid tokens"""
394
```