22Author : zhangxianbing
33Date : 2020-12-27 09:22:14
44LastEditors : zhangxianbing
5- LastEditTime : 2021-02-07 10:10:55
5+ LastEditTime : 2021-03-02 15:18:06
66Description : JSONPath
77"""
88__version__ = "1.0.3"
@@ -36,7 +36,7 @@ def create_logger(name: str = None, level: Union[int, str] = logging.INFO):
3636 return logger
3737
3838
39- LOG = create_logger ("jsonpath" , os .getenv ("PYLOGLEVEL" , "INFO" ))
39+ logger = create_logger ("jsonpath" , os .getenv ("PYLOGLEVEL" , "INFO" ))
4040
4141
4242class ExprSyntaxError (Exception ):
@@ -49,15 +49,19 @@ class JSONPath:
4949 "PATH" : "All path of specific values." ,
5050 }
5151
52+ # common patterns
5253 SEP = ";"
53- # regex patterns
54- REP_PICKUP_QUOTE = re .compile (r"['](.*?)[']" )
55- REP_PICKUP_BRACKET = re .compile (r"[\[](.*?)[\]]" )
56- REP_PUTBACK_QUOTE = re .compile (r"#Q(\d+)" )
57- REP_PUTBACK_BRACKET = re .compile (r"#B(\d+)" )
5854 REP_DOUBLEDOT = re .compile (r"\.\." )
5955 REP_DOT = re .compile (r"(?<!\.)\.(?!\.)" )
6056
57+ # save special patterns
58+ REP_GET_QUOTE = re .compile (r"['](.*?)[']" )
59+ REP_PUT_QUOTE = re .compile (r"#Q(\d+)" )
60+ REP_GET_BRACKET = re .compile (r"[\[](.*?)[\]]" )
61+ REP_PUT_BRACKET = re .compile (r"#B(\d+)" )
62+ REP_GET_PAREN = re .compile (r"[\(](.*?)[\)]" )
63+ REP_PUT_PAREN = re .compile (r"#P(\d+)" )
64+
6165 # operators
6266 REP_SLICE_CONTENT = re .compile (r"^(-?\d*)?:(-?\d*)?(:-?\d*)?$" )
6367 REP_SELECT_CONTENT = re .compile (r"^([\w.']+)(, ?[\w.']+)+$" )
@@ -76,7 +80,7 @@ def __init__(self, expr: str):
7680 expr = self ._parse_expr (expr )
7781 self .segments = expr .split (JSONPath .SEP )
7882 self .lpath = len (self .segments )
79- LOG .debug (f"segments : { self .segments } " )
83+ logger .debug (f"segments : { self .segments } " )
8084
8185 def parse (self , obj , result_type = "VALUE" ):
8286 if not isinstance (obj , (list , dict )):
@@ -94,36 +98,46 @@ def parse(self, obj, result_type="VALUE"):
9498 return self .result
9599
96100 def _parse_expr (self , expr ):
97- LOG .debug (f"before expr : { expr } " )
101+ logger .debug (f"before expr : { expr } " )
98102
99- expr = JSONPath .REP_PICKUP_QUOTE .sub (self ._f_pickup_quote , expr )
100- expr = JSONPath .REP_PICKUP_BRACKET .sub (self ._f_pickup_bracket , expr )
103+ expr = JSONPath .REP_GET_QUOTE .sub (self ._get_quote , expr )
104+ expr = JSONPath .REP_GET_BRACKET .sub (self ._get_bracket , expr )
105+ expr = JSONPath .REP_GET_PAREN .sub (self ._get_paren , expr )
101106 expr = JSONPath .REP_DOUBLEDOT .sub (f"{ JSONPath .SEP } ..{ JSONPath .SEP } " , expr )
102107 expr = JSONPath .REP_DOT .sub (JSONPath .SEP , expr )
103- expr = JSONPath .REP_PUTBACK_BRACKET .sub (self ._f_putback_bracket , expr )
104- expr = JSONPath .REP_PUTBACK_QUOTE .sub (self ._f_putback_quote , expr )
108+ expr = JSONPath .REP_PUT_PAREN .sub (self ._put_paren , expr )
109+ expr = JSONPath .REP_PUT_BRACKET .sub (self ._put_bracket , expr )
110+ expr = JSONPath .REP_PUT_QUOTE .sub (self ._put_quote , expr )
105111 if expr .startswith ("$;" ):
106112 expr = expr [2 :]
107113
108- LOG .debug (f"after expr : { expr } " )
114+ logger .debug (f"after expr : { expr } " )
109115 return expr
110116
111- def _f_pickup_quote (self , m ):
117+ def _get_quote (self , m ):
112118 n = len (self .subx ["#Q" ])
113119 self .subx ["#Q" ].append (m .group (1 ))
114120 return f"#Q{ n } "
115121
116- def _f_pickup_bracket (self , m ):
122+ def _put_quote (self , m ):
123+ return self .subx ["#Q" ][int (m .group (1 ))]
124+
125+ def _get_bracket (self , m ):
117126 n = len (self .subx ["#B" ])
118127 self .subx ["#B" ].append (m .group (1 ))
119128 return f".#B{ n } "
120129
121- def _f_putback_quote (self , m ):
122- return self .subx ["#Q" ][int (m .group (1 ))]
123-
124- def _f_putback_bracket (self , m ):
130+ def _put_bracket (self , m ):
125131 return self .subx ["#B" ][int (m .group (1 ))]
126132
133+ def _get_paren (self , m ):
134+ n = len (self .subx ["#P" ])
135+ self .subx ["#P" ].append (m .group (1 ))
136+ return f"(#P{ n } )"
137+
138+ def _put_paren (self , m ):
139+ return self .subx ["#P" ][int (m .group (1 ))]
140+
127141 @staticmethod
128142 def _f_brackets (m ):
129143 ret = "__obj"
@@ -147,7 +161,7 @@ def _getattr(obj: dict, path: str):
147161 try :
148162 r = r .get (k )
149163 except (AttributeError , KeyError ) as err :
150- LOG .error (err )
164+ logger .error (err )
151165 return None
152166
153167 return r
@@ -167,7 +181,7 @@ def _filter(self, obj, i: int, path: str, step: str):
167181 try :
168182 r = eval (step , None , {"__obj" : obj })
169183 except Exception as err :
170- LOG .error (err )
184+ logger .error (err )
171185 if r :
172186 self ._trace (obj , i , path )
173187
@@ -185,7 +199,7 @@ def _trace(self, obj, i: int, path):
185199 self .result .append (obj )
186200 elif self .result_type == "PATH" :
187201 self .result .append (path )
188- LOG .debug (f"path: { path } | value: { obj } " )
202+ logger .debug (f"path: { path } | value: { obj } " )
189203 return
190204
191205 step = self .segments [i ]
@@ -256,18 +270,18 @@ def _trace(self, obj, i: int, path):
256270 if isinstance (obj , dict ):
257271 obj_ = {}
258272 for k in step [1 :- 1 ].split ("," ):
259- obj_ [k ] = obj . get ( k )
273+ obj_ [k ] = self . _getattr ( obj , k )
260274 self ._trace (obj_ , i + 1 , path )
261275 else :
262- raise ExprSyntaxError ("field-extractor must acting on list or dict" )
276+ raise ExprSyntaxError ("field-extractor must acting on dict" )
263277
264278 return
265279
266280
267281if __name__ == "__main__" :
268282 with open ("test/data/2.json" , "rb" ) as f :
269283 d = json .load (f )
270- D = JSONPath ("$[bicycle, scores] " ).parse (d , "VALUE" )
284+ D = JSONPath ("$. scores[/(score)].(score) " ).parse (d , "VALUE" )
271285 print (D )
272286 for v in D :
273287 print (v )
0 commit comments