【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))

 

 

执行结果

 

 

 

 

参考地址:https://www.jianshu.com/p/e6fb96b6288e

posted @ 2023-04-25 15:46  Phoenixy  阅读(1229)  评论(0编辑  收藏  举报