json - Find and modify python nested dictionary (key, value) -
i have json file need update. converting python dict (nested) update it. here input, dept. i'm sure there better way this, don't know.
ultimatley want able perfom create/delete action in addition update.
here script , input file.
# find target value in nested key value chain # replace old value newvalue import json pprint import pprint d1 = open('jinputstack.json', 'r') d1 = json.load(d1) def traverse(obj, path=none, callback=none): """ traverse python object structure, calling callback function every element in structure, , inserting return value of callback new value. """ if path none: path = [] if isinstance(obj, dict): value = {k: traverse(v, path + [k], callback) k, v in obj.items()} elif isinstance(obj, list): value = [traverse(elem, path + [[]], callback) elem in obj] else: value = obj if callback none: # print("starting value found-----------------------------------------------------") print(value) return value else: print(path, value) return callback(path, value) def traverse_modify(obj, target_path, action): """ traverses arbitrary object structure , performs given action on value, replacing node action's return value. """ target_path = to_path(target_path) pprint(value) pprint(target_path) def transformer(path, value): if path == target_path: print(action) d2 = data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"].update(action) return d2 else: return value return traverse(obj, callback=transformer) def to_path(path): """ helper function, converting path strings path lists. >>> to_path('foo') ['foo'] >>> to_path('foo.bar') ['foo', 'bar'] >>> to_path('foo.bar[]') ['foo', 'bar', []] """ if isinstance(path, list): return path # in list format def _iter_path(path): #pprint(path.split) parts in path.split('[]'): part in parts.strip('.').split('.'): yield part yield [] return list(_iter_path(path))[:-1] def updateit(newvalue): data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"] = newvalue print(data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"]) return data["groups"][0]["properties"][1]["value"]["data"][2]["object"]["name"] traverse_modify(d1, d1["groups"][0]["properties"][1]["value"]["data"][1]["object"]["name"], updateit("xxxxxxxxxxxxxx")) json_data = json.dumps(data) f = open("jinputstack.json","w") f.write(json_data) f.close()
jinputstack.json = { "groups": [ { "name": "group1", "properties": [ { "name": "test-key-string", "value": { "type": "string", "encoding": "utf-8", "data": "value1" } }, { "name": "test-key-valuearray", "value": { "type": "valuearray", "data": [ { "data": true }, { "type": "blob", "object": { "name": "john su", "age": 25, "salary": 104000.45, "married": false, "gender": "male" } } ] } } ], "groups": [ { "name": "group-child", "properties": [ { "name": "test-key-string" }, { "name": "test-key-list", "value": { "type": "list", "data": [ "string1", "string2", "string3" ] } } ] } ] }, { "name": "group2", "properties": [ { "name": "test-key2-string", "value": { "type": "string", "encoding": "utf-8", "data": "value2" } }, { "name": "microbox" } ] } ] }
credit goes original author: vincent driessen
i think best way convert json object xml , use elementtree , xpath parse , modify object. later can revert json if need:
import json xmljson import parker lxml.etree import element dataxml = parker.etree(datajson, root=element('root')) print(dataxml.find('.//data//name').text) # john su dataxml.find('.//data//name').text = "joan d'arc" print(dataxml.find('.//data//name').text) # joan d'arc print(json.dumps(parker.data(dataxml)))
there packages xpath on json string directly. 1 of them, jsonpath-rw
changes syntax. prefer stick standard xpath syntax.
from jsonpath_rw import jsonpath, parse expr = parse('$..data..name') # notice . $ , / . # confusing enough? expr.find(datajson)[0] = 'yyyy' print(expr.find(datajson)[0].value) # john su
another 1 xjpath
simple , perhaps easier learn, not give difference doing now.
import xjpath xj = xjpath.xjpath(datajson) print(xj['groups.@0.properties.@1.value.data.@1.object.name']) # not different code: print(data["groups"][0]["properties"][1]["value"]["data"][1]["object"]["name"])
i hope helps.
Comments
Post a Comment