Skip to content

Commit 2f493e0

Browse files
committed
Add parent, children and parts to JSONPathMatch.
1 parent 7166662 commit 2f493e0

File tree

8 files changed

+670
-491
lines changed

8 files changed

+670
-491
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@
77
- Added support for function extensions.
88
- Added the built-in `length()` function.
99
- Added the built-in `count()` function. `count()` is an alias for `length()`
10-
- Added the built-in `keys()` function (non-standard).
1110
- Support filters without parentheses.
1211
- Adhere to IETF JSONPath draft escaping in quoted property selectors.
1312
- Handle UTF-16 surrogate pairs in quoted property selectors.
1413

14+
**Features**
15+
16+
- Added the built-in `keys()` function.
17+
- Added `parent` and `children` properties to `JSONPathMatch`. Now we can traverse the "document tree" after finding matches.
18+
- Added a `parts` property to `JSONPathMatch`. `parts` is a tuple of `int`s, `slice`s and `str`s that can be used with `JSONPathEnvironment.getitem()` to get the matched object from the original data structure, or equivalent data structures. It is the keys, indices and slices that make up a concrete path.
19+
1520
## Version 0.2.0
1621

1722
**Fixes**

jsonpath/match.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,55 @@
11
"""The JSONPath match object, as returned from :meth:`JSONPath.finditer`."""
2+
from __future__ import annotations
23

34
from typing import Any
5+
from typing import List
46
from typing import Mapping
7+
from typing import Optional
58
from typing import Sequence
9+
from typing import Tuple
610
from typing import Union
711

812
FilterContextVars = Mapping[str, Any]
9-
10-
# TODO: store path as tuple of things
11-
# TODO: store reference to parent
12-
# TODO: store list of children
13+
PathPart = Union[int, slice, str]
1314

1415

1516
class JSONPathMatch:
1617
"""Bind a matched object to its path."""
1718

18-
__slots__ = ("_filter_context", "obj", "path", "root")
19+
__slots__ = (
20+
"_filter_context",
21+
"children",
22+
"obj",
23+
"parent",
24+
"parts",
25+
"path",
26+
"root",
27+
)
1928

2029
def __init__(
2130
self,
2231
*,
2332
filter_context: FilterContextVars,
2433
obj: object,
34+
parent: Optional[JSONPathMatch],
2535
path: str,
36+
parts: Tuple[PathPart, ...],
2637
root: Union[Sequence[Any], Mapping[str, Any]],
2738
) -> None:
28-
self.path = path
39+
self._filter_context = filter_context
40+
self.children: List[JSONPathMatch] = []
2941
self.obj = obj
42+
self.parent = parent
43+
self.parts = parts
44+
self.path = path
3045
self.root = root
31-
self._filter_context = filter_context
3246

3347
def __str__(self) -> str:
3448
return f"{_truncate(str(self.obj), 5)!r} @ {_truncate(self.path, 5)}"
3549

50+
def add_child(self, *children: JSONPathMatch) -> None:
51+
self.children.extend(children)
52+
3653
def filter_context(self) -> FilterContextVars:
3754
""""""
3855
return self._filter_context

jsonpath/path.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@ def finditer(
6767

6868
matches: Iterable[JSONPathMatch] = [
6969
JSONPathMatch(
70-
path=self.env.root_token,
70+
filter_context=filter_context or {},
7171
obj=data,
72+
parent=None,
73+
path=self.env.root_token,
74+
parts=(),
7275
root=data,
73-
filter_context=filter_context or {},
7476
)
7577
]
7678

@@ -108,10 +110,12 @@ async def finditer_async(
108110

109111
async def root_iter() -> AsyncIterable[JSONPathMatch]:
110112
yield JSONPathMatch(
111-
path=self.env.root_token,
113+
filter_context=filter_context or {},
112114
obj=data,
115+
parent=None,
116+
path=self.env.root_token,
117+
parts=(),
113118
root=data,
114-
filter_context=filter_context or {},
115119
)
116120

117121
matches: AsyncIterable[JSONPathMatch] = root_iter()

0 commit comments

Comments
 (0)