Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9783d9a
Implement callable subscripts
markborkum Mar 7, 2019
9ee388e
Resolve autopep8 and pylint warnings
markborkum Mar 7, 2019
75143b3
Resolve pylint warnings
markborkum Mar 7, 2019
8ab8dbd
Resolve flake8 E501 warning
markborkum Mar 7, 2019
bf59e66
Call length() on JSON string
markborkum Mar 7, 2019
e18cb34
Resolve pylint warnings
markborkum Mar 7, 2019
a99a7b1
Resolve pylint warnings
markborkum Mar 8, 2019
af3f4db
Fix pre-commit and update pylint
dmlb2000 Mar 8, 2019
701f713
Merge branch 'feat-callables' of ssh://github.com:22/markborkum/pytho…
dmlb2000 Mar 8, 2019
9eaf2f6
Resolve pylint warnings
markborkum Mar 8, 2019
ea0325b
Resolve pylint warnings
markborkum Mar 8, 2019
a10adbc
Implement subscript(number[,number]) callable subscript
markborkum Mar 8, 2019
22ffc34
100% coverage
markborkum Mar 8, 2019
8e564af
Resolve pylint warnings
markborkum Mar 8, 2019
aae0ba9
Resolve pylint warnings
markborkum Mar 8, 2019
ec63125
Resolve pylint warnings
markborkum Mar 8, 2019
82aab10
Resolve pylint warnings
markborkum Mar 8, 2019
5d8d94e
Resolve pylint warnings
markborkum Mar 8, 2019
644424a
Resolve pylint warnings
markborkum Mar 8, 2019
489eee9
Resolve pylint warnings
markborkum Mar 8, 2019
962ad26
Resolve pylint warnings
markborkum Mar 8, 2019
2fdddd2
Rename callable subscript classes
markborkum Mar 8, 2019
63e0e57
Implement Array.entries, Array.keys and Array.values methods
markborkum Mar 8, 2019
161b2fe
Update README.md
markborkum Mar 8, 2019
82cd59b
Remove unnecessary diffs
markborkum Mar 8, 2019
dbb36b8
Rename __match__ to __call__
markborkum Mar 8, 2019
5ffb7af
Move callable subscript names into class properties
markborkum Mar 8, 2019
95f141b
Construct dictionary of callable subscripts
markborkum Mar 8, 2019
f1608bd
Resolve pylint warnings
markborkum Mar 8, 2019
127311d
Update README.md
markborkum Mar 8, 2019
8574707
Update typing for callable subscripts
markborkum Mar 9, 2019
4627cf3
track provenance of callable subscript arguments
markborkum Mar 9, 2019
c74d480
Resolve pylint warnings
markborkum Mar 9, 2019
5d6cb6a
Rename "number" to "int"
markborkum Mar 9, 2019
ac83692
Merge remote-tracking branch 'upstream/master' into mark-feat-callables
dmlb2000 Apr 8, 2019
558b385
Document callables in README
markborkum May 11, 2019
e151421
Transform list into table
markborkum May 11, 2019
1d3f6cf
Add link to pull request
markborkum May 11, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 122 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This repository contains an implementation of [JSONPath](http://goessner.net/art

### `Path` class

The `jsonpath2.Path.Path` class represents a JSONPath.
The `jsonpath2.path.Path` class represents a JSONPath.

```python
>>> s = '{"hello":"Hello, world!"}'
Expand All @@ -24,7 +24,7 @@ The `jsonpath2.Path.Path` class represents a JSONPath.
['$["hello"]']
```

This class is constructed with respect to the given instance of the `jsonpath2.Path.RootNode` class (viz., the `root_node` property).
This class is constructed with respect to the given instance of the `jsonpath2.nodes.root.RootNode` class (viz., the `root_node` property).

#### `parse_str(strdata)` class method

Expand All @@ -37,7 +37,7 @@ Parse the contents of the given file and return a new instance of this class.
#### `match(root_value)` instance method

Match the given JSON data structure against this instance.
For each match, yield an instance of the `jsonpath2.Node.MatchData` class.
For each match, yield an instance of the `jsonpath2.node.MatchData` class.

#### `__eq__(other)` instance method

Expand All @@ -53,7 +53,7 @@ The root node of the abstract syntax tree for this instance.

### `Node` abstract class

The `jsonpath2.Node.Node` class represents the abstract syntax tree for a JSONPath.
The `jsonpath2.node.Node` class represents the abstract syntax tree for a JSONPath.

#### `__eq__(other)` instance method

Expand All @@ -66,15 +66,15 @@ Yields the lexer tokens for the string representation of this instance.
#### `match(root_value, current_value)` instance method

Match the given root and current JSON data structures against this instance.
For each match, yield an instance of the `jsonpath2.Node.MatchData` class.
For each match, yield an instance of the `jsonpath2.node.MatchData` class.

#### `tojsonpath()` instance method

Returns the string representation of this instance.

### `MatchData` class

The `jsonpath2.Node.MatchData` class represents the JSON value and context for a JSONPath match.
The `jsonpath2.node.MatchData` class represents the JSON value and context for a JSONPath match.

This class is constructed with respect to a root JSON value, a current JSON value, and an abstract syntax tree node.

Expand Down Expand Up @@ -111,10 +111,125 @@ The abstract syntax tree node.
| JSONPath Filter Expression | Description |
| - | - |
| `$` or `@` | nested JSONPath (returns `true` if any match exists; otherwise, returns `false`) |
| `=`, `!=`, `>`, `>=`, `<`, `<=` | binary operator, where left-hand operand is a nested JSONPath and right-right operand is a JSON value (returns `true` if any match exists; otherwise, returns `false`) |
| `=`, `!=`, `>`, `>=`, `<`, `<=` | binary operator, where left- and right-hand operands are nested JSONPaths or JSON values (returns `true` if any match exists; otherwise, returns `false`) |
| `and`, `or`, `not` | Boolean operator, where operands are JSONPath filter expressions |
| `(` ... `)` | parentheses |

## Functions

> See [#14](https://github.com/pacifica/python-jsonpath2/pull/14) for more information.

The syntax for a function call is the name of the function followed by the arguments in parentheses, i.e., `name(arg1, arg2, ..., argN)`, where the arguments are either JSONPaths or JSON values.

```python
>>> s = '{"hello":"Hello, world!"}'
'{"hello":"Hello, world!"}'
>>> import json
>>> d = json.loads(s)
{'hello':'Hello, world!'}
>>> from jsonpath2.path import Path
>>> p = Path.parse_str('$["hello"][length()]')
<jsonpath2.path.Path object>
>>> list(map(lambda match_data: match_data.current_value, p.match(d)))
[13]
>>> list(map(lambda match_data: match_data.node.tojsonpath(), p.match(d)))
['$["hello"][length()]']
```

| JavaScript Function | Signature |
| - | - |
| [`Array.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length) | `length(): int` |
| [`Array.prototype.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries) | `entries(): List[Tuple[int, Any]]` |
| [`Array.prototype.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys) | `keys(): List[int]` |
| [`Array.prototype.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values) | `values(): List[Any]` |
| [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) | `entries(): List[Tuple[str, Any]]` |
| [`Object.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) | `keys(): List[str]` |
| [`Object.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values) | `values(): List[Any]` |
| [`string.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length) | `length(): int` |
| [`String.prototype.charAt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt) | `charAt(index: int): str` |
| [`String.prototype.substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) | `substring(indexStart: int, indexEnd: Optional[int]): str` |

<!-- | `Array.prototype.concat()` | |
| `Array.prototype.fill()` | |
| `Array.prototype.flat()` | |
| `Array.prototype.includes()` | |
| `Array.prototype.indexOf()` | |
| `Array.prototype.join()` | |
| `Array.prototype.lastIndexOf()` | |
| `Array.prototype.slice()` | |
| `Array.prototype.sort()` | |
| `Array.prototype.splice()` | |
| `JSON.parse()` | |
| `JSON.stringify()` | |
| `Math.abs()` | |
| `Math.acos()` | |
| `Math.acosh()` | |
| `Math.asin()` | |
| `Math.asinh()` | |
| `Math.atan()` | |
| `Math.atan2()` | |
| `Math.atanh()` | |
| `Math.cbrt()` | |
| `Math.ceil()` | |
| `Math.clz32()` | |
| `Math.cos()` | |
| `Math.cosh()` | |
| `Math.exp()` | |
| `Math.expm1()` | |
| `Math.floor()` | |
| `Math.fround()` | |
| `Math.hypot()` | |
| `Math.imul()` | |
| `Math.log()` | |
| `Math.log10()` | |
| `Math.log1p()` | |
| `Math.log2()` | |
| `Math.max()` | |
| `Math.min()` | |
| `Math.pow()` | |
| `Math.random()` | |
| `Math.round()` | |
| `Math.sign()` | |
| `Math.sin()` | |
| `Math.sinh()` | |
| `Math.sqrt()` | |
| `Math.tan()` | |
| `Math.tanh()` | |
| `Math.trunc()` | |
| `Number.isFinite()` | |
| `Number.isInteger()` | |
| `Number.isNaN()` | |
| `Number.isSafeInteger()` | |
| `Number.parseFloat()` | |
| `Number.parseInt()` | |
| `String.prototype.codeCharAt()` | |
| `String.prototype.codePointAt()` | |
| `String.prototype.concat()` | |
| `String.prototype.endsWith()` | |
| `String.prototype.includes()` | |
| `String.prototype.indexOf()` | |
| `String.prototype.lastIndexOf()` | |
| `String.prototype.localeCompare()` | |
| `String.prototype.match()` | |
| `String.prototype.normalize()` | |
| `String.prototype.padEnd()` | |
| `String.prototype.padStart()` | |
| `String.prototype.repeat()` | |
| `String.prototype.replace()` | |
| `String.prototype.search()` | |
| `String.prototype.slice()` | |
| `String.prototype.split()` | |
| `String.prototype.startsWith()` | |
| `String.prototype.toLocaleLowerCase()` | |
| `String.prototype.toLocaleUpperCase()` | |
| `String.prototype.toLowerCase()` | |
| `String.prototype.toUpperCase()` | |
| `String.prototype.trim()` | |
| `String.prototype.trimEnd()` | |
| `String.prototype.trimStart()` | | -->

In the above table, the type aliases (`Any`, `List`, `Optional` and `Tuple`) are defined by the [`typing`](https://docs.python.org/3/library/typing.html) module from the Python Standard Library.

## Grammar and parser

The [ANTLR v4](https://github.com/antlr/antlr4) grammar for JSONPath is available at `jsonpath2/parser/JSONPath.g4`.
Expand Down
7 changes: 6 additions & 1 deletion jsonpath2/parser/JSONPath.g4
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ subscriptables
: BRACKET_LEFT subscriptable ( COMMA subscriptable )* BRACKET_RIGHT
;

subscriptableArguments
: PAREN_LEFT ( jsonpath__ ( COMMA jsonpath__ )* )? PAREN_RIGHT
;

subscriptableBareword
: ID
: ID subscriptableArguments?
| WILDCARD_SUBSCRIPT
;

Expand All @@ -66,6 +70,7 @@ subscriptable
| WILDCARD_SUBSCRIPT
| QUESTION PAREN_LEFT expression PAREN_RIGHT
| jsonpath_
| ID subscriptableArguments
;

sliceable
Expand Down
Loading