Skip to content

Commit a188803

Browse files
committed
refactor: finish operator: wildcard & recursive descent
1 parent 1092628 commit a188803

File tree

4 files changed

+37
-28
lines changed

4 files changed

+37
-28
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ uninstall:
1111
pip uninstall jsonpath
1212

1313
test:
14-
pytest tests -vv -s
14+
pytest test -vv -s
1515

1616
clean:
1717
rm -rf $(PYCACHE_DIR) ${PYTEST_DIR}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ A more powerful JSONPath implementations in modern python.
2121
- [ ] Powerful filtering function, including multi-selection, inverse-selection filtering.
2222
- [ ] Powerful sorting function, including sorting by multiple fields, ascending and descending order.
2323

24+
## Issues
25+
26+
- Not support parent operator.
27+
2428
## Examples
2529

2630
JSON format data:

jsonpath/__init__.py

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Author : zhangxianbing1
33
Date : 2020-12-27 09:22:14
44
LastEditors : zhangxianbing1
5-
LastEditTime : 2020-12-30 17:39:37
5+
LastEditTime : 2020-12-31 11:07:08
66
Description : JSONPath
77
"""
88
__version__ = "1.0.0"
@@ -65,10 +65,11 @@ def __init__(self, expr: str, *, result_type="VALUE"):
6565
expr = self._parse_expr(expr)
6666
self.ops = expr.split(SEP)
6767
self.oplen = len(self.ops)
68+
print(f"operations : {self.ops}")
6869

6970
def _parse_expr(self, expr):
7071
if __debug__:
71-
print(f"before expr: {expr}")
72+
print(f"before expr : {expr}")
7273

7374
expr = REP_PICKUP_QUOTE.sub(self._f_pickup_quote, expr)
7475
expr = REP_PICKUP_BRACKET.sub(self._f_pickup_bracket, expr)
@@ -80,7 +81,7 @@ def _parse_expr(self, expr):
8081
expr = expr[2:]
8182

8283
if __debug__:
83-
print(f"after expr: {expr}")
84+
print(f"after expr : {expr}")
8485
return expr
8586

8687
def _f_pickup_quote(self, m):
@@ -108,7 +109,7 @@ def parse(self, obj):
108109
else:
109110
self.result = []
110111

111-
self._trace(obj, 0)
112+
self._operate(obj, 0)
112113

113114
return self.result
114115

@@ -117,47 +118,48 @@ def _op(self, i):
117118
return self.ops[i]
118119
return None
119120

120-
def _trace(self, obj, idx, op=None):
121-
# obj - 当前处理对象
122-
# idx - 当前操作在操作集中的序号
123-
# op - 覆盖idx指定操作的操作
121+
def _traverse(self, f, obj, idx: int):
122+
if isinstance(obj, list):
123+
for i, v in enumerate(obj):
124+
f(v, idx)
125+
elif isinstance(obj, dict):
126+
for k, v in obj.items():
127+
f(v, idx)
128+
129+
def _operate(self, obj, idx: int):
130+
"""Perform operation on object.
131+
132+
Args:
133+
obj ([type]): current operating object
134+
idx (int): current operation specified by index in self.ops
135+
"""
124136

125137
# store
126138
if idx >= self.oplen:
127139
self.result.append(obj)
128140
print(obj)
129141
return
130142

131-
op = op or self.ops[idx]
143+
op = self.ops[idx]
132144

133-
# getall
145+
# wildcard
134146
if op == "*":
135-
if isinstance(obj, list):
136-
for i, v in enumerate(obj):
137-
self._trace(v, idx + 1)
138-
elif isinstance(obj, dict):
139-
for k, v in obj.items():
140-
self._trace(v, idx + 1)
141-
142-
# traverse
147+
self._traverse(self._operate, obj, idx + 1)
148+
149+
# recursive descent
143150
elif op == "..":
144-
self._trace(obj, idx + 1)
145-
if isinstance(obj, list):
146-
for i, v in enumerate(obj):
147-
self._trace(v, idx + 1, "..")
148-
elif isinstance(obj, dict):
149-
for k, v in obj.items():
150-
self._trace(v, idx + 1, "..")
151+
self._operate(obj, idx + 1)
152+
self._traverse(self._operate, obj, idx)
151153

152154
# get value from dict
153155
elif isinstance(obj, dict) and op in obj:
154-
self._trace(obj[op], idx + 1)
156+
self._operate(obj[op], idx + 1)
155157

156158
# get value from list
157159
elif isinstance(obj, list) and op.isdigit():
158160
ikey = int(op)
159161
if ikey < len(obj):
160-
self._trace(obj[ikey], idx + 1)
162+
self._operate(obj[ikey], idx + 1)
161163

162164
# elif key.startswith("?(") and key.endswith(")"): # filter
163165
# pass

test/conftest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
"bicycle": {"color": "red", "price": 19.95},
3737
}
3838

39+
prices = [8.95, 12.99, 8.99, 22.99, 19.95]
40+
3941

4042
@pytest.fixture(
4143
params=[
@@ -44,6 +46,7 @@
4446
TestCase("$[book]", data, [data["book"]]),
4547
TestCase("$.'a.b c'", data, [data["a.b c"]]),
4648
TestCase("$['a.b c']", data, [data["a.b c"]]),
49+
TestCase("$..price", data, prices),
4750
]
4851
)
4952
def cases(request):

0 commit comments

Comments
 (0)