-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjpath.py
117 lines (104 loc) · 4.26 KB
/
jpath.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
########################################################################
#
# jpath-py
# An XPath-like querying interface for JSON objects
#
# author: Vasileios Mitrousis
# email: [email protected]
#
# The software is given as is, no guarantees from the author
# Licenced under Apache 2.0 licence
#
########################################################################
debug = False
# This function will accept a JSON document and a path /x/y/z[4]/*
# and will return you the actual value of the key(s)
def get_dict_value(doc, path, leaf=None):
if len(path.strip()) == 0:
return doc
path_splits = path.split('/')
for i, key in enumerate(path_splits):
if debug: print 'key processing: ' + key
if not doc:
return None
if '[' in key and ']' in key and i != len(path_splits)-1:
# array element
if debug: print 'array element'
idx = int(key[key.index('[')+1:key.index(']')])
key = key[:key.index('[')]
if debug: print 'key stripped: ' + key
if not doc.get(key):
return None
if isinstance(doc[key], list):
if debug: print 'is an array'
if idx >= len(doc[key]):
# index out of bounds
if debug: print 'out of bounds'
return None
doc = doc[key][idx]
else:
# single object, accept 0 index only
if debug: print 'single object'
if idx > 0:
return None
doc = doc[key]
elif key == '*':
# '*' has 2 meanings. The whole array,
# or the whole object if it is the last key
if debug: print 'wildcard key'
if i == len(path_splits) - 1:
# it is the last element, push the whole object
if debug: print 'last element'
else:
# '*' requires the whole array in this case
if debug: print 'getting the whole array'
if isinstance(doc, list):
if debug: print 'is type of array'
else:
if debug: print 'is not type of array, constructing it manually'
doc = [doc]
idx = -1
item_arr = []
recon_path = '/'.join(path_splits[i+1:])
if ']' == recon_path[-1]:
# we need indexed result
if debug: print 'getting indexed result'
idx = int(recon_path[recon_path.index('[')+1:recon_path.index(']')])
recon_path = recon_path[:recon_path.index('[')]
for k, item in enumerate(doc):
val = get_dict_value(item, recon_path, leaf)
if val:
item_arr.append(val)
if idx != -1:
if idx < len(item_arr):
return item_arr[idx]
return None
return item_arr
else:
if debug: print 'normal key: ' + key
if isinstance(doc, list):
if debug: print 'pointing to an array'
print "Warning: '%s' array was detected but not expected. Returning first item." % path_splits[i-1]
if len(doc) > 0:
doc = doc[0].get(key)
else:
if debug: print 'getting object normaly'
doc = doc.get(key)
if i == len(path_splits) - 1:
if debug: print 'it is the last component'
if isinstance(doc, list):
if debug: print 'it is a list, generate a @Val array'
try:
doc = [d[leaf] for d in doc if d]
except:
if debug: print "1,", path, doc
#raw_input()
else:
if debug: print 'final object @Val'
if doc and leaf:
try:
doc = doc[leaf]
except Exception, e:
print 'jpath_error:', e
#raw_input()
return doc