297 lines
11 KiB
Python
297 lines
11 KiB
Python
# uncompyle6 version 3.9.2
|
|
# Python bytecode version base 3.7.0 (3394)
|
|
# Decompiled from: Python 3.8.19 (default, Mar 20 2024, 15:27:52)
|
|
# [Clang 14.0.6 ]
|
|
# Embedded file name: /var/user/app/device_supervisorbak/device_supervisor/lib/jsonpath.py
|
|
# Compiled at: 2024-04-18 03:12:55
|
|
# Size of source mod 2**32: 11901 bytes
|
|
"""
|
|
An XPath for JSON
|
|
|
|
A port of the Perl, and JavaScript versions of JSONPath
|
|
see http://goessner.net/articles/JsonPath/
|
|
|
|
Based on on JavaScript version by Stefan Goessner at:
|
|
https://goessner.net/articles/JsonPath/
|
|
http://code.google.com/p/jsonpath/
|
|
and Perl version by Kate Rhodes at:
|
|
http://github.com/masukomi/jsonpath-perl/tree/master
|
|
|
|
Python3 compatibily by Per J. Sandstrom
|
|
"""
|
|
from __future__ import print_function
|
|
__author__ = "Phil Budne"
|
|
__revision__ = "$Revision: 1.17 $"
|
|
__version__ = "0.82"
|
|
import re, sys
|
|
__all__ = [
|
|
"jsonpath"]
|
|
if sys.version_info[0] == 3:
|
|
xrange = range
|
|
|
|
def normalize(x):
|
|
"""normalize the path expression; outside jsonpath to allow testing"""
|
|
subx = []
|
|
|
|
def f1(m):
|
|
n = len(subx)
|
|
g1 = m.group(1)
|
|
subx.append(g1)
|
|
ret = "[#%d]" % n
|
|
return ret
|
|
|
|
x = re.sub("[\\['](\\??\\(.*?\\))[\\]']", f1, x)
|
|
x = re.sub("'?(?<!@)\\.'?|\\['?", ";", x)
|
|
x = re.sub(";;;|;;", ";..;", x)
|
|
x = re.sub(";$|'?\\]|'$", "", x)
|
|
|
|
def f2(m):
|
|
g1 = m.group(1)
|
|
return subx[int(g1)]
|
|
|
|
x = re.sub("#([0-9]+)", f2, x)
|
|
return x
|
|
|
|
|
|
def jsonpath(obj, expr, result_type='VALUE', debug=0, use_eval=True):
|
|
"""traverse JSON object using jsonpath expr, returning values or paths"""
|
|
|
|
def s(x, y):
|
|
"""concatenate path elements"""
|
|
return str(x) + ";" + str(y)
|
|
|
|
def isint(x):
|
|
"""check if argument represents a decimal integer"""
|
|
return x.isdigit()
|
|
|
|
def as_path(path):
|
|
"""convert internal path representation to
|
|
"full bracket notation" for PATH output"""
|
|
p = "$"
|
|
for piece in path.split(";")[1[:None]]:
|
|
if isint(piece):
|
|
p += "[%s]" % piece
|
|
else:
|
|
p += "['%s']" % piece
|
|
|
|
return p
|
|
|
|
def store(path, object):
|
|
if result_type == "VALUE":
|
|
result.append(object)
|
|
else:
|
|
if result_type == "IPATH":
|
|
result.append(path.split(";")[1[:None]])
|
|
else:
|
|
result.append(as_path(path))
|
|
return path
|
|
|
|
def trace(expr, obj, path):
|
|
if debug:
|
|
print("trace", expr, "/", path)
|
|
elif expr:
|
|
x = expr.split(";")
|
|
loc = x[0]
|
|
x = ";".join(x[1[:None]])
|
|
if debug:
|
|
print("\t", loc, type(obj))
|
|
if loc == "*":
|
|
|
|
def f03(key, loc, expr, obj, path):
|
|
if debug > 1:
|
|
print("\tf03", key, loc, expr, path)
|
|
trace(s(key, expr), obj, path)
|
|
|
|
walk(loc, x, obj, path, f03)
|
|
else:
|
|
if loc == "..":
|
|
trace(x, obj, path)
|
|
|
|
def f04(key, loc, expr, obj, path):
|
|
if debug > 1:
|
|
print("\tf04", key, loc, expr, path)
|
|
elif isinstance(obj, dict):
|
|
if key in obj:
|
|
trace(s("..", expr), obj[key], s(path, key))
|
|
elif key < len(obj):
|
|
trace(s("..", expr), obj[key], s(path, key))
|
|
|
|
walk(loc, x, obj, path, f04)
|
|
else:
|
|
if loc == "!":
|
|
|
|
def f06(key, loc, expr, obj, path):
|
|
if isinstance(obj, dict):
|
|
trace(expr, key, path)
|
|
|
|
walk(loc, x, obj, path, f06)
|
|
else:
|
|
if isinstance(obj, dict) and loc in obj:
|
|
trace(x, obj[loc], s(path, loc))
|
|
else:
|
|
if isinstance(obj, list) and isint(loc):
|
|
iloc = int(loc)
|
|
if debug:
|
|
print("----->", iloc, len(obj))
|
|
if len(obj) > iloc:
|
|
trace(x, obj[iloc], s(path, loc))
|
|
else:
|
|
if loc.startswith("("):
|
|
if loc.endswith(")"):
|
|
if debug > 1:
|
|
print("index", loc)
|
|
e = evalx(loc, obj)
|
|
trace(s(e, x), obj, path)
|
|
return
|
|
elif loc.startswith("?("):
|
|
if loc.endswith(")"):
|
|
if debug > 1:
|
|
print("filter", loc)
|
|
|
|
def f05(key, loc, expr, obj, path):
|
|
if debug > 1:
|
|
print("f05", key, loc, expr, path)
|
|
elif isinstance(obj, dict):
|
|
eval_result = evalx(loc, obj[key])
|
|
else:
|
|
eval_result = evalx(loc, obj[int(key)])
|
|
if eval_result:
|
|
trace(s(key, expr), obj, path)
|
|
|
|
loc = loc[2[:-1]]
|
|
walk(loc, x, obj, path, f05)
|
|
return
|
|
m = re.match("(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$", loc)
|
|
if m:
|
|
if isinstance(obj, (dict, list)):
|
|
|
|
def max(x, y):
|
|
if x > y:
|
|
return x
|
|
return y
|
|
|
|
def min(x, y):
|
|
if x < y:
|
|
return x
|
|
return y
|
|
|
|
objlen = len(obj)
|
|
s0 = m.group(1)
|
|
s1 = m.group(2)
|
|
s2 = m.group(3)
|
|
start = int(s0) if s0 else 0
|
|
end = int(s1) if s1 else objlen
|
|
step = int(s2) if s2 else 1
|
|
if start < 0:
|
|
start = max(0, start + objlen)
|
|
else:
|
|
start = min(objlen, start)
|
|
if end < 0:
|
|
end = max(0, end + objlen)
|
|
else:
|
|
end = min(objlen, end)
|
|
for i in xrange(start, end, step):
|
|
trace(s(i, x), obj, path)
|
|
|
|
else:
|
|
return
|
|
if loc.find(",") >= 0:
|
|
for piece in re.split("'?,'?", loc):
|
|
if debug > 1:
|
|
print("piece", piece)
|
|
trace(s(piece, x), obj, path)
|
|
|
|
else:
|
|
store(path, obj)
|
|
|
|
def walkParse error at or near `COME_FROM' instruction at offset 92_2
|
|
|
|
def evalx(loc, obj):
|
|
"""eval expression"""
|
|
if debug:
|
|
print("evalx", loc)
|
|
else:
|
|
loc = loc.replace("@.length", "len(__obj)")
|
|
loc = loc.replace("&&", " and ").replace("||", " or ")
|
|
|
|
def notvar(m):
|
|
return "'%s' not in __obj" % m.group(1)
|
|
|
|
loc = re.sub("!@\\.([a-zA-Z@_0-9-]*)", notvar, loc)
|
|
|
|
def varmatch(m):
|
|
|
|
def brackets(elts):
|
|
ret = "__obj"
|
|
for e in elts:
|
|
if isint(e):
|
|
ret += "[%s]" % e
|
|
else:
|
|
ret += "['%s']" % e
|
|
|
|
return ret
|
|
|
|
g1 = m.group(1)
|
|
elts = g1.split(".")
|
|
if elts[-1] == "length":
|
|
return "len(%s)" % brackets(elts[1[:-1]])
|
|
return brackets(elts[1[:None]])
|
|
|
|
loc = re.sub("(?<!\\\\)(@\\.[a-zA-Z@_.0-9]+)", varmatch, loc)
|
|
loc = re.sub("(?<!\\\\)@", "__obj", loc).replace("\\@", "@")
|
|
if not use_eval:
|
|
if debug:
|
|
print("eval disabled")
|
|
raise Exception("eval disabled")
|
|
if debug:
|
|
print("eval", loc)
|
|
try:
|
|
v = eval(loc, caller_globals, {"__obj": obj})
|
|
except Exception as e:
|
|
try:
|
|
if debug:
|
|
print(repr(e))
|
|
return False
|
|
finally:
|
|
e = None
|
|
del e
|
|
|
|
if debug:
|
|
print("->", v)
|
|
return v
|
|
|
|
caller_globals = sys._getframe(1).f_globals
|
|
result = []
|
|
if expr:
|
|
if obj:
|
|
cleaned_expr = normalize(expr)
|
|
if cleaned_expr.startswith("$;"):
|
|
cleaned_expr = cleaned_expr[2[:None]]
|
|
trace(cleaned_expr, obj, "$")
|
|
if len(result) > 0:
|
|
return result
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
import json
|
|
except ImportError:
|
|
import simplejson as json
|
|
|
|
import sys
|
|
if len(sys.argv) < 3 or len(sys.argv) > 4:
|
|
sys.stdout.write("Usage: jsonpath.py FILE PATH [OUTPUT_TYPE]\n")
|
|
sys.exit(1)
|
|
object = json.load(file(sys.argv[1]))
|
|
path = sys.argv[2]
|
|
format = "VALUE"
|
|
if len(sys.argv) > 3:
|
|
format = sys.argv[3]
|
|
value = jsonpath(object, path, format)
|
|
if not value:
|
|
sys.exit(1)
|
|
f = sys.stdout
|
|
json.dump(value, f, sort_keys=True, indent=1)
|
|
f.write("\n")
|
|
sys.exit(0) |