【Python】操作复杂嵌套的json数据
1、相关文章
递归获取所有key-value值:https://www.cnblogs.com/phoenixy/p/17126455.html
2、对复杂的json进行增删改查
① 获取数据
# -*- coding: UTF-8 -*- import json from jsonpath_ng import parse from aa_demo.base.logger import * class json_labor_tools: """ 操作Json对象 注意事项: 1.不同层级同名key的value均会被修改, 如果修改单独的key 需要指定层级 2。属性访问的时候,对json节点名称有比较高的要求 """ def __init__(self, buffer: dict = None): """ :param buffer: 固有的属性, 访问不存在的属性时自动访问此属性 """ self._buffer = buffer def __getitem__(self, key): """ getitem复写 实现下标的访问""" return self.get(key) def __getattr__(self, key): """ 属性访问 节点名称需要符合json要求 """ if key in self.__dir__() or key == '_buffer': return super().__getattr__(key) return self.get(key) def get(self, key: str, num=0): """ :param key: 需要获取的key, 如果存在同名的key取第一个值 :param num: 0 取首个数据值, -1 取全部数据值 (当num个数大于列表内容相当于=0)) :return: """ if not key.startswith('$..'): condition = '$..' + key else: condition = key ret = [] for match in parse(condition).find(self.__dict__['_buffer']): ret.append(match.value) if not ret: logs.error("key: {} 不存在, 请检查参数或文件内~".format(key)) else: return ret if num == -1 else ret[num] if 0 < num < len(ret) else ret[0] if __name__ == "__main__": """run""" j = json.load(open('../data/demo/demo.json')) logs.debug("json 原文件内容: {}".format(j)) logs.debug("="*80 + "\n") """获取复杂json的key-value""" logs.debug("下标获取:{}".format(json_labor_tools(j)['addr9'])) logs.debug("属性访问:{}".format(json_labor_tools(j).addr8)) logs.debug("方法获取:{}".format(json_labor_tools(j).get('addr7'))) logs.debug("方法获取多个:{}".format(json_labor_tools(j).get('listAddr', -1))) """保存文件""" # json.dump(j, open('../data/demo/demo.json', 'w+'), ensure_ascii=False, indent=4, sort_keys=True) logs.debug("="*80 + "\n") logs.debug("json 新文件内容: {}".format(j))
执行结果:
② 修改数据
# -*- coding: UTF-8 -*- import json from jsonpath_ng import parse from aa_demo.base.logger import * class json_labor_tools: """ 操作Json对象 注意事项: 1.不同层级同名key的value均会被修改, 如果修改单独的key 需要指定层级 2。属性访问的时候,对json节点名称有比较高的要求 """ def __init__(self, buffer: dict = None): """ :param buffer: 固有的属性, 访问不存在的属性时自动访问此属性 """ self._buffer = buffer def __setitem__(self, key, value): """ etitem复写 实现下标的访问""" return self.set(key, value) def __setattr__(self, key: str, value): """ 属性访问 节点名称需要符合json要求 """ if key in self.__dir__() or key == '_buffer': super().__setattr__(key, value) return else: self.set(key, value) def set(self, key: str, value): """ :param key: 需要修改的key, 如果存在同名的key 修改全部 :param value: 修改后的内容 :return: """ if not key.startswith('$..'): condition = '$..' + key else: condition = key parse(condition).update(self.__dict__['_buffer'], value) return self if __name__ == "__main__": """run""" j = json.load(open('../data/demo/demo.json')) logs.debug("json 原文件内容: {}".format(j)) logs.debug("="*80 + "\n") """修改复杂json的key-value""" json_labor_tools(j)["adminAddr"] = "修改后的地址" json_labor_tools(j)["listAddr"] = "set-listAddr" json_labor_tools(j).listName = "修改后的名字" json_labor_tools(j).set("listAge", "110") json_labor_tools(j).set("listAge4", "不存在") """保存文件""" # json.dump(j, open('../data/demo/demo.json', 'w+'), ensure_ascii=False, indent=4, sort_keys=True) logs.debug("="*80 + "\n") logs.debug("json 新文件内容: {}".format(j))
执行结果
③ 删除数据
# -*- coding: UTF-8 -*- import json from jsonpath_ng import parse from aa_demo.base.logger import * class json_labor_tools: """ 操作Json对象 注意事项: 1.不同层级同名key的value均会被修改, 如果修改单独的key 需要指定层级 2。属性访问的时候,对json节点名称有比较高的要求 """ def __init__(self, buffer: dict = None): """ :param buffer: 固有的属性, 访问不存在的属性时自动访问此属性 """ self._buffer = buffer def __delattr__(self, key): """ 属性访问 节点名称需要符合json要求 """ if key in self.__dir__() or key == '_buffer': return super().__getattr__(key) return self.pops(key) def pops(self, key: str): """ :param key: 需要删除的key, 如果存在同名的key 删除全部 :return: """ if not key.startswith('$..'): condition = '$..' + key else: condition = key ret = [] for match in parse(condition).find(self.__dict__['_buffer']): ret.append(match.context.value) if not ret: logs.error("key: {} 不存在, 请检查参数或文件内~".format(key)) else: for i in range(len(ret)): # ret[i].pop(key) del ret[i][key] return self if __name__ == "__main__": """run""" j = json.load(open('../data/demo/demo.json')) logs.debug("json 原文件内容: {}".format(j)) logs.debug("="*80 + "\n") """修改复杂json的key-value""" del json_labor_tools(j).adminAddr del json_labor_tools(j).addr1 json_labor_tools(j).pops("adminTel").pops("addr2").pops("listAddr") """保存文件""" # json.dump(j, open('../data/demo/demo.json', 'w+'), ensure_ascii=False, indent=4, sort_keys=True) logs.debug("="*80 + "\n") logs.debug("json 新文件内容: {}".format(j))
执行结果
3、完整代码实现
# -*- coding: UTF-8 -*- import json from jsonpath_ng import parse from aa_demo.base.logger import * class json_labor_tools: """ 操作Json对象 注意事项: 1.不同层级同名key的value均会被修改, 如果修改单独的key 需要指定层级 2。属性访问的时候,对json节点名称有比较高的要求 """ def __init__(self, buffer: dict = None): """ :param buffer: 固有的属性, 访问不存在的属性时自动访问此属性 """ self._buffer = buffer def __getitem__(self, key): """ getitem复写 实现下标的访问""" return self.get(key) def __setitem__(self, key, value): """ etitem复写 实现下标的访问""" return self.set(key, value) def __getattr__(self, key): """ 属性访问 节点名称需要符合json要求 """ if key in self.__dir__() or key == '_buffer': return super().__getattr__(key) return self.get(key) def __setattr__(self, key: str, value): """ 属性访问 节点名称需要符合json要求 """ if key in self.__dir__() or key == '_buffer': super().__setattr__(key, value) return else: self.set(key, value) def __delattr__(self, key): """ 属性访问 节点名称需要符合json要求 """ if key in self.__dir__() or key == '_buffer': return super().__getattr__(key) return self.pops(key) def get(self, key: str, num=0): """ :param key: 需要获取的key, 如果存在同名的key取第一个值 :param num: 0 取首个数据值, -1 取全部数据值 (当num个数大于列表内容相当于=0)) :return: """ if not key.startswith('$..'): condition = '$..' + key else: condition = key ret = [] for match in parse(condition).find(self.__dict__['_buffer']): ret.append(match.value) if not ret: logs.error("key: {} 不存在, 请检查参数或文件内~".format(key)) else: return ret if num == -1 else ret[num] if 0 < num < len(ret) else ret[0] def set(self, key: str, value): """ :param key: 需要修改的key, 如果存在同名的key 修改全部 :param value: 修改后的内容 :return: """ if not key.startswith('$..'): condition = '$..' + key else: condition = key parse(condition).update(self.__dict__['_buffer'], value) return self def pops(self, key: str): """ :param key: 需要删除的key, 如果存在同名的key 删除全部 :return: """ if not key.startswith('$..'): condition = '$..' + key else: condition = key ret = [] for match in parse(condition).find(self.__dict__['_buffer']): ret.append(match.context.value) if not ret: logs.error("key: {} 不存在, 请检查参数或文件内~".format(key)) else: for i in range(len(ret)): # ret[i].pop(key) del ret[i][key] return self def add(self, items: dict = None): """ :param items: 需要添加键值对 :return: """ if isinstance(items, dict) and not None: self.__dict__['_buffer'].update(items) else: logs.error("未添加成功,请检查item参数是否符合要求") return self if __name__ == "__main__": """run""" j = json.load(open('../data/demo/demo.json')) logs.debug("json 原文件内容: {}".format(j)) logs.debug("="*80 + "\n") # 获取value # logs.debug("获取到的 listAddr: {}".format(json_labor_tools(j).get("listAddr"))) # logs.debug("获取到的全部 listAddr: {}".format(json_labor_tools(j).get("listAddr", -1))) # logs.debug("listAddr: {}".format(json_labor_tools(json_labor_tools(j).get('listbak')).get("listAddr"))) # # 修改value # json_labor_tools(j).set("adminAddr", "qipan"). # json_labor_tools(j).set("adminAddr", "tianjin").set("adminPhone", "15700010002") # json_labor_tools(j).set("adminAge", "32").set("list", [1, 2, 3, 4, 4, 6]) # # 添加key-value # json_labor_tools(j).add({"listadd": "add"}) # json_labor_tools(j).add({"listadd": ["add", "add2"]}).add({"name": "add"}) # json_labor_tools(json_labor_tools(j).get('listbak')).set("listAge", 32) # # 删除key-value # json_labor_tools(j).pops('listAddr') json_labor_tools(j).set("adminAge", "30").add({"addAdminName": "addVlue"}).pops("addr1") # # getitem和setitem复写, 下标访问 # logs.debug("获取 adminAge = {}".format(json_labor_tools(j)['adminAge'])) # logs.debug("获取 listTel = {}".format(json_labor_tools(j)['listTel'])) # 属性访问及修改内容 不指定层级会修改全部同名key的value # logs.debug("获取到的 adminAddr: {}".format(json_labor_tools(j).adminAddra)) logs.debug("获取到的 listName: {}".format(json_labor_tools(j).listName)) json_labor_tools(j).adminPhone = "13612340000" # json_labor_tools(json_labor_tools(j).listbak[0]).listPhone = '13212348877' # del json_labor_tools(j).adminAddr del json_labor_tools(j).listAddr """保存文件""" # json.dump(j, open('../data/demo/demo.json', 'w+'), ensure_ascii=False, indent=4, sort_keys=True) logs.debug("="*80 + "\n") logs.debug("json 新文件内容: {}".format(j))
执行结果
-------------------------------------------------------------------------------------
如果万事开头难 那请结局一定圆满 @ Phoenixy
-------------------------------------------------------------------------------------