Skip to content

Commit cfa891c

Browse files
committed
More docs [skip ci]
1 parent dd37e3d commit cfa891c

File tree

2 files changed

+100
-89
lines changed

2 files changed

+100
-89
lines changed

docs/singular_query_selector.md

Lines changed: 0 additions & 43 deletions
This file was deleted.

docs/syntax.md

Lines changed: 100 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# JSONPath Syntax
22

3-
By default, Python JSONPath extends the RFC 9535 specification with a few additional features and relaxed rules, making it more forgiving in everyday use. If you need strict compliance with RFC 9535, you can enable strict mode, which enforces the standard without these extensions. In this guide, we first outline the standard syntax (see the specification for the formal definition), and then describe the non-standard extensions and their semantics in detail.
3+
By default, Python JSONPath extends the RFC 9535 specification with a few additional features and relaxed rules. If you need strict compliance with RFC 9535, you can enable strict mode, which enforces the standard without these extensions. In this guide, we first outline the standard syntax (see the specification for the formal definition), and then describe the non-standard extensions and their semantics in detail.
44

55
## JSONPath Terminology
66

@@ -241,7 +241,7 @@ $..price
241241

242242
## Non-standard selectors and identifiers
243243

244-
The selectors and identifiers described in this section are an extension to RFC 9535. They are enabled by default. See [#strict-mode] for details on how to use JSONPath following RFC 9535 strictly.
244+
The selectors and identifiers described in this section are an extension to RFC 9535. They are enabled by default. See [#strict-mode] for details on how to use JSONPath without these extensions.
245245

246246
### Key selector
247247

@@ -373,6 +373,8 @@ filter-selector = "~?" S logical-expr
373373

374374
### Singular query selector
375375

376+
**_New in version 2.0.0_**
377+
376378
The singular query selector consist of an embedded absolute singular query, the result of which is used as an object member name or array element index.
377379

378380
If the embedded query resolves to a string or int value, at most one object member value or array element value is selected. Otherwise the singular query selector selects nothing.
@@ -456,7 +458,7 @@ current-key-identifier = "#"
456458

457459
**_New in version 0.11.0_**
458460

459-
The pseudo root identifier (`^`) behaves like the standard root identifier (`$`), but conceptually wraps the target JSON document in a single-element array. This allows the root document itself to be addressed by selectors such as filters, which normally only apply to elements within arrays.
461+
The pseudo root identifier (`^`) behaves like the standard root identifier (`$`), but conceptually wraps the target JSON document in a single-element array. This allows the root document itself to be conditionally selected by filters.
460462

461463
#### Syntax
462464

@@ -469,31 +471,111 @@ pseudo-root-identifier = "^"
469471

470472
#### Examples
471473

472-
TODO
474+
```json title="Example JSON data"
475+
{ "a": { "b": 42 }, "n": 7 }
476+
```
477+
478+
| Query | Result | Result Path | Comment |
479+
| -------------------------- | ------------------------------ | ----------- | ----------------------------------- |
480+
| `^[[email protected] > 7]` | `{ "a": { "b": 42 } }` | `^[0]` | Conditionally select the root value |
481+
| `^[[email protected] > value(^.*.n)]` | `{ "a": { "b": 42 }, "n": 7 }` | `^[0]` | Embedded pseudo root query |
473482

474483
### Filter context identifier
475484

476485
The filter context identifier (`_`) starts an embedded query, similar to the root identifier (`$`) and current node identifier (`@`), but targets JSON-like data passed as the `filter_context` argument to [`findall()`](api.md#jsonpath.JSONPath.findall) and [`finditer()`](api.md#jsonpath.JSONPath.finditer).
477486

478487
#### Syntax
479488

480-
TODO
489+
```
490+
current-node-identifier = "@"
491+
extra-context-identifier = "_"
492+
493+
filter-query = rel-query / extra-context-query / jsonpath-query
494+
rel-query = current-node-identifier segments
495+
extra-context-query = extra-context-identifier segments
496+
497+
singular-query = rel-singular-query / abs-singular-query / extra-context-singular-query
498+
rel-singular-query = current-node-identifier singular-query-segments
499+
abs-singular-query = root-identifier singular-query-segments
500+
501+
extra-context-singular-query = extra-context-identifier singular-query-segments
502+
```
481503

482504
#### Examples
483505

484-
TODO
506+
```json title="Example JSON data"
507+
{ "a": [{ "b": 42 }, { "b": 3 }] }
508+
```
509+
510+
```json title="Extra JSON data"
511+
{ "c": 42 }
512+
```
513+
514+
| Query | Result | Result Path | Comment |
515+
| ------------------ | ------------- | ----------- | -------------------------------------------- |
516+
| `$.a[[email protected] == _.c]` | `{ "b": 42 }` | `$['a'][0]` | Comparison with extra context singular query |
485517

486518
## Non-standard operators
487519

488-
TODO
520+
In addition to the operators described below, the standard _logical and_ operator (`&&`) is aliased as `and`, the standard _logical or_ operator (`||`) is aliased as `or`, and `null` is aliased as `nil` and `none`.
489521

490-
### Lists (`[1, 2, 10:20]`)
522+
Also, `true`, `false`, `null` and their aliases can start with an upper case letter.
491523

492-
Select multiple indices, slices or properties using list notation (sometimes known as a "union" or "segment", we use "union" to mean something else).
524+
### Membership operators
525+
526+
The membership operators test whether one value occurs within another.
527+
528+
An infix expression using `contains` evaluates to true if the right-hand side is a member of the left-hand side, and false otherwise.
529+
530+
- If the left-hand side is an object and the right-hand side is a string, the result is true if the object has a member with that name.
531+
- If the left-hand side is an array, the result is true if any element of the array is equal to the right-hand side.
532+
- For scalars (strings, numbers, booleans, null), `contains` always evaluates to false.
533+
534+
The `in` operator is equivalent to `contains` with operands reversed. This makes `contains` and `in` symmetric, so either form may be used depending on which reads more naturally in context.
535+
536+
A list literal is a comma separated list of JSONPath expression literals. List should appear on the left-hand side of `contains` or the right-hand side of `in`.
537+
538+
#### Syntax
493539

494-
```text
495-
$..products.*.[title, price]
496540
```
541+
basic-expr = paren-expr /
542+
comparison-expr /
543+
membership-expr /
544+
test-expr
545+
546+
membership-expr = comparable S membership-op S comparable
547+
548+
membership-operator = "contains" / "in"
549+
550+
membership-operand = literal /
551+
singular-query / ; singular query value
552+
function-expr / ; ValueType
553+
list-literal
554+
555+
list-literal = "[" S literal *(S "," S literal) S "]"
556+
```
557+
558+
#### Examples
559+
560+
```json title="Example JSON data"
561+
{
562+
"x": [{ "a": ["foo", "bar"] }, { "a": ["bar"] }],
563+
"y": [{ "a": { "foo": "bar" } }, { "a": { "bar": "baz" } }],
564+
"z": [{ "a": "foo" }, { "a": "bar" }]
565+
}
566+
```
567+
568+
| Query | Result | Result Path | Comment |
569+
| ------------------------------------- | ----------------------- | ----------- | ------------------------------------ |
570+
| `$.x[[email protected] contains 'foo']` | `{"a": ["foo", "bar"]}` | `$['x'][0]` | Array contains string literal |
571+
| `$.y[[email protected] contains 'foo']` | `{"a": ["foo", "bar"]}` | `$['y'][0]` | Object contains string literal |
572+
| `$.x[?'foo' in @.a]` | `{"a": ["foo", "bar"]}` | `$['x'][0]` | String literal in array |
573+
| `$.y[?'foo' in @.a]` | `{"a": ["foo", "bar"]}` | `$['y'][0]` | String literal in object |
574+
| `$.z[?(['bar', 'baz'] contains @.a)]` | `{"a": "bar"}` | `$['z'][1]` | List literal contains embedded query |
575+
576+
### The regex operator
577+
578+
TODO
497579

498580
### Union (`|`) and intersection (`&`)
499581

@@ -513,38 +595,10 @@ $.categories[?(@.name == 'footwear')].products.* & $.categories[?(@.name == 'hea
513595

514596
Note that `|` and `&` are not allowed inside filter expressions.
515597

516-
## Notable differences
517-
518-
This is a list of things that you might find in other JSONPath implementation that we don't support (yet).
519-
520-
- We don't support extension functions of the form `selector.func()`.
521-
- We always return a list of matches from `jsonpath.findall()`, never a scalar value.
522-
- We do not support arithmetic in filter expression.
523-
- We don't allow dotted array indices. An array index must be surrounded by square brackets.
524-
- Python JSONPath is strictly read only. There are no update "selectors", but we do provide methods for converting `JSONPathMatch` instances to `JSONPointer`s, and a `JSONPatch` builder API for modifying JSON-like data structures using said pointers.
525-
526-
And this is a list of areas where we deviate from [RFC 9535](https://datatracker.ietf.org/doc/html/rfc9535). See [jsonpath-rfc9535](https://github.com/jg-rp/python-jsonpath-rfc9535) for an alternative implementation of JSONPath that does not deviate from RFC 9535.
527-
528-
- The root token (default `$`) is optional and paths starting with a dot (`.`) are OK. `.thing` is the same as `$.thing`, as is `thing`, `$[thing]` and `$["thing"]`.
529-
- The built-in `match()` and `search()` filter functions use Python's standard library `re` module, which, at least, doesn't support Unicode properties. We might add an implementation of `match()` and `search()` using the third party [regex](https://pypi.org/project/regex/) package in the future.
530-
- We don't check `match()` and `search()` regex arguments against RFC 9485. Any valid Python pattern is allowed.
531-
- We don't require property names to be quoted inside a bracketed selection, unless the name contains reserved characters.
532-
- We don't require the recursive descent segment to have a selector. `$..` is equivalent to `$..*`.
533-
- We support explicit comparisons to `undefined` as well as implicit existence tests.
534-
- Float literals without a fractional digit are OK or leading digit. `1.` is equivalent to `1.0`.
535-
- We treat literals (such as `true` and `false`) as valid "basic" expressions. For example, `$[?true || false]`, without an existence test or comparison either side of logical _or_, does not raise a syntax error.
536-
- By default, `and` is equivalent to `&&` and `or` is equivalent to `||`.
537-
- `none` and `nil` are aliases for `null`.
538-
- `null` (and its aliases), `true` and `false` can start with an upper or lower case letter.
539-
- We don't treat some invalid `\u` escape sequences in quoted name selectors and string literals as an error. We match the behavior of the JSON decoder in Python's standard library, which is less strict than RFC 9535.
540-
541-
And this is a list of features that are uncommon or unique to Python JSONPath.
542-
543-
- We support membership operators `in` and `contains`, plus list/array literals.
544-
- `|` 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.
545-
- `&` 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.
546-
- `#` is the current key/property or index identifier when filtering a mapping or sequence.
547-
- `_` is a filter context identifier. With usage similar to `$` and `@`, `_` exposes arbitrary data from the `filter_context` argument to `findall()` and `finditer()`.
548-
- `~` is a "keys" or "properties" selector.
549-
- `^` is a "fake root" identifier. It is equivalent to `$`, but wraps the target JSON document in a single-element array, so the root value can be conditionally selected with a filter selector.
550-
- `=~` is the the regex match operator, matching a value to a JavaScript-style regex literal.
598+
## Other differences
599+
600+
This is a list of areas where Python JSONPath is more relaxed than [RFC 9535](https://datatracker.ietf.org/doc/html/rfc9535).
601+
602+
- The root token (`$`) is optional and paths starting with a dot (`.`) are OK. `.thing` is the same as `$.thing`, as is `thing` and `$["thing"]`.
603+
- Leading and trailing whitespace is OK.
604+
- We support explicit comparisons to `undefined` (aka `missing`) as well as implicit existence tests.

0 commit comments

Comments
 (0)