Skip to content

Commit ac080d9

Browse files
committed
docs: syntax guide stub [skip ci]
1 parent 53ddce0 commit ac080d9

3 files changed

Lines changed: 186 additions & 3 deletions

File tree

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,6 @@ print(products)
101101

102102
## Next Steps
103103

104-
Have a read through the [Quick Start](quickstart.md) and [High Level API Reference](api.md).
104+
Have a read through the [Quick Start](quickstart.md) and [High Level API Reference](api.md), or the default [JSONPath Syntax](syntax.md) supported by Python JSONPath.
105105

106106
If you're interested in customizing JSONPath, take a look at [Advanced Usage](advanced.md) and the [Low Level API Reference](custom_api.md).

docs/quickstart.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ for match in matches:
8383
print(matches)
8484
```
8585

86-
The string representation of a [`JSONPathMatch`](api.md#jsonpath.JSONPathMatch) shows the matched object and the canonical path to that object in the given data.
86+
The string representation of a [`JSONPathMatch`](api.md#jsonpath.JSONPathMatch) shows the matched object and the canonical path to that object.
8787

8888
```text
8989
'Sue' @ $['users'][0]['name']

docs/syntax.md

Lines changed: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,186 @@
11
# JSONPath Syntax
22

3-
TODO
3+
Python JSONPath's default syntax is an opinionated combination of JSONPath features from existing, popular implementations, and much of the [IETF JSONPath draft](https://datatracker.ietf.org/doc/html/draft-ietf-jsonpath-base-11). If you're already familiar with JSONPath syntax, skip to [notable differences](#notable-differences).
4+
5+
Imagine a JSON document as a tree structure, where each object (mapping) and array can contain more objects, arrays and scalar values. Every object, array and scalar value is a node in the tree, and the outermost object or array is the "root" node.
6+
7+
For our purposes, a JSON "document" could be a file containing valid JSON data, a Python string containing valid JSON data, or a Python `Object` made up of dictionaries (or any [Mapping](https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes)), lists (or any [Sequence](https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes)), strings, etc.
8+
9+
We chain _selectors_ together to retrieve nodes from the target document. Each selector operates on the nodes matched by preceding selectors. What follows is a description of those selectors.
10+
11+
## Selectors
12+
13+
### Root (`$`)
14+
15+
`$` refers to the first node in the target document, be it an object or an array. Unless referencing the root node from inside a filter expression, `$` is optional. The following two examples are equivalent.
16+
17+
```text
18+
$.categories.*.name
19+
```
20+
21+
```text
22+
categories.*.name
23+
```
24+
25+
An empty path or a path containing just the root (`$`) selector returns the input data in its entirety.
26+
27+
### Properties (`.thing`, `[thing]` or `['thing']`)
28+
29+
Select nodes by property/key name using dot notation (`.something`) or bracket notation (`[something]`). If a target property/key contains reserved characters, it must use bracket notation and be enclosed in quotes (`['thing']`).
30+
31+
A dot in front of bracket notation is OK, but unnecessary. The following examples are equivalent.
32+
33+
```text
34+
$.categories[0].name
35+
```
36+
37+
```text
38+
$.categories[0][name]
39+
```
40+
41+
```text
42+
$.categories[0]['name']
43+
```
44+
45+
### Array indices (`.0`, `[0]` or `[-1]`)
46+
47+
Select an item from an array by its index. Indices are zero-based and enclosed in brackets. If the index is negative, items are selected from the end of the array. Considering example data from the top of this page, the following examples are equivalent.
48+
49+
```text
50+
$.categories[0]
51+
```
52+
53+
```text
54+
$.categories.0
55+
```
56+
57+
```text
58+
$.categories[-1]
59+
```
60+
61+
### Wildcard (`.*` or `[*]`)
62+
63+
Select all elements from an array or all values from an object using `*`. These two examples are equivalent.
64+
65+
```text
66+
$.categories[0].products.*
67+
```
68+
69+
```text
70+
$.categories[0].products[*]
71+
```
72+
73+
### Slices (`[0:-1]` or `[-1:0:-1]`)
74+
75+
Select a range of elements from an array using slice notation. The start index, stop index and step are all optional. These examples are equivalent.
76+
77+
```text
78+
$.categories[0:]
79+
```
80+
81+
```text
82+
$.categories[0:-1:]
83+
```
84+
85+
```text
86+
$.categories[0:-1:1]
87+
```
88+
89+
```text
90+
$.categories[::]
91+
```
92+
93+
### Lists (`[1, 2, 10:20]`)
94+
95+
Select multiple indices, slices or properties using list notation (sometimes known as a "union" or "segment", we use "union" to mean something else).
96+
97+
```text
98+
$..products.*.[title, price]
99+
```
100+
101+
### Recursive descent (`..`)
102+
103+
The `..` selector visits every node beneath the current selection. If a property selector, using dot notation, follows `..`, the dot is optional. These two examples are equivalent.
104+
105+
```text
106+
$..title
107+
```
108+
109+
```text
110+
$...title
111+
```
112+
113+
### Filters (`[?(EXPRESSION)]`)
114+
115+
Filters allow you to remove nodes from a selection using a Boolean expression. Within a filter, `@` refers to the current node and `$` refers to the root node in the target document. `@` and `$` can be used to select nodes as part of the expression. Since version 0.3.0, the parentheses are optional, as per the IETF JSONPath draft. These two examples are equivalent.
116+
117+
```text
118+
$..products[?(@.price < $.price_cap)]
119+
```
120+
121+
```text
122+
$..products[[email protected] < $.price_cap]
123+
```
124+
125+
Comparison operators include `==`, `!=`, `<`, `>`, `<=` and `>=`. Plus `<>` as an alias for `!=`.
126+
127+
`in` and `contains` are membership operators. `left in right` is equivalent to `right contains left`.
128+
129+
`&&` and `||` are logical operators, `and` and `or` work too.
130+
131+
`=~` matches the left value with a regular expression literal. Regular expressions use a syntax similar to that found in JavaScript, where the pattern to match is surrounded by slashes, optionally followed by flags.
132+
133+
```text
134+
$..products[?(@.description =~ /.*trainers/i)]
135+
```
136+
137+
Filters can use [function extensions](#function-extensions) too.
138+
139+
### Union (`|`) and intersection (`&`)
140+
141+
Union (`|`) and intersection (`&`) are similar to Python's set operations, but we don't dedupe the matches (matches will often contain unhashable objects).
142+
143+
The `|` operator combines matches from two or more paths. This example selects a single list of all prices, plus the price cap as the last element.
144+
145+
```text
146+
$..products.*.price | $.price_cap
147+
```
148+
149+
The `&` operator produces matches that are common to both left and right paths. This example would select the list of products that are common to both the "footwear" and "headwear" categories.
150+
151+
```text
152+
$.categories.*[?(@.name == 'footwear')].products.* & $.categories.*[?(@.name == 'headwear')].products.*
153+
```
154+
155+
Note that `|` and `&` are not allowed inside filter expressions.
156+
157+
## Function extensions
158+
159+
[Filters](#filters-expression) can call functions, be they built-in functions or custom functions. The result of a function call will be evaluated as part of the filter expression.
160+
161+
TODO:
162+
163+
## Notable differences
164+
165+
This is a list of things that you might find in other JSONPath implementation that we don't support (yet).
166+
167+
- We don't support extension functions of the form `selector.func()`.
168+
- We always return a list of matches from `jsonpath.findall()`, never a scalar value.
169+
- We do not support arithmetic in filter expression.
170+
- Python JSONPath is strictly read only. There are no update "selectors".
171+
172+
And this is a list of areas where we deviate from the [IETF JSONPath draft](https://datatracker.ietf.org/doc/html/draft-ietf-jsonpath-base-11).
173+
174+
- For now, the only built-in function extension is `length()`.
175+
- We don't require filters that use a function extension to include a comparison operator.
176+
- Whitespace is mostly insignificant unless inside quotes.
177+
- The root token (default `$`) is optional.
178+
- Paths starting with a dot (`.`) are OK. `.thing` is the same as `$.thing`, as is `thing`, `$[thing]` and `$["thing"]`.
179+
- Nested filters are not supported.
180+
- We don't treat filter expressions without a comparison as existence test, but an "is truthy" test. See the "Existence of non-singular queries" example in the IETF JSONPath draft.
181+
182+
And this is a list of features that are uncommon or unique to Python JSONPath.
183+
184+
- `|` is a union operator, where matches from two or more JSONPaths are combined. This is not part of the Python API, but built-in to the JSONPath syntax.
185+
- `&` is an intersection operator, where we exclude matches that don't exist in both left and right paths. This is not part of the Python API, but built-in to the JSONPath syntax.
186+
- `#` is a filter context selector. With usage similar to `$` and `@`, `#` exposes arbitrary data from the `filter_context` argument to `findall()` and `finditer()`.

0 commit comments

Comments
 (0)