【问题标题】:How to remove a node from a dict using jsonpath-ng?如何使用 jsonpath-ng 从字典中删除节点?
【发布时间】:2022-11-21 18:02:02
【问题描述】:

在 Python 中,我有一个字典列表,我想从列表中的每个字典中删除给定的节点。我对这些词典一无所知,除了它们都具有相同(未知)的模式。要删除的节点可以在字典中的任何位置,它由 JSONPath 表达式指定。

例子:

输入数据:

[
  { "top": { "lower": 1, "other": 1 } },
  { "top": { "lower": 2, "other": 4 } },
  { "top": { "lower": 3, "other": 9 } }
]

待移除节点:$.*.top.lower

预期结果:

[
  { "top": { "other": 1 } },
  { "top": { "other": 4 } },
  { "top": { "other": 9 } }
]

使用 jsonpath 库我的第一次尝试是这样的:

from jsonpath import JSONPath

def remove_node_from_dict(data, node):
    node_key = JSONPath(node).segments.pop()
    for record in data:
        del record[node_key]

但这仅在要删除的节点位于字典的顶层时才有效。 在研究解决方案时,我遇到了 jsonpath-ng 库,它声称具有“更新或删除树中节点的能力”。但是,我找不到关于此的任何文档 - 它是如何完成的?

编辑:

基于this 对相关问题的回答,我找到了一个解决方案,该解决方案至少适用于使用普通 Python(不是 jsonpath-ng 库)的简单路径(无过滤器等)。这对我的用例来说就足够了。我仍然想学习如何以更通用的方式使用 jsonpath-ng 进行操作。

【问题讨论】:

    标签: python jsonpath jsonpath-ng


    【解决方案1】:

    这是我过去使用过的一个天真的解决方案:

    def remove_matched_element(path, spec):
        _new_spec = copy.deepcopy(spec)
        jep = jp.parse(path)
        for match in jep.find(spec):
            _t_path = "$"
            spec_path = _new_spec
            spec_path_parent = None
            for pe in str(match.full_path).split("."):
                if _t_path != "$" and type(jp.parse(_t_path).find(_new_spec)[0].value) == list:
                    _t_path = f"{_t_path}{'.'}{pe}"
                    _idx = int(pe.replace("[", "").replace("]", ""))
                    spec_path_parent = spec_path
                    spec_path = spec_path[_idx]
                elif _t_path != "$" and type(jp.parse(_t_path).find(_new_spec)[0].value) == dict and pe == "[0]":
                    keyp = list(jp.parse(_t_path).find(_new_spec)[0].value.keys())[0]
                    _idx = keyp
                    _t_path = f"{_t_path}.{keyp}"
                    spec_path_parent = spec_path
                    spec_path = spec_path[keyp]
                else:
                    if type(spec_path) == list:
                        _idx = int(pe.replace("[", "").replace("]", ""))
                        _t_path = f"{_t_path}[{_idx}]"
                    else:
                        _idx = pe
                        _t_path = f"{_t_path}{'.'}{pe}"
                    spec_path_parent = spec_path
                    spec_path = spec_path[_idx]
            spec_path_parent.pop(_idx)
        return _new_spec
    
    
    def test_soc_sol():
        spec = [
            {"top": {"lower": 1, "other": 1}},
            {"top": {"lower": 2, "other": 4}},
            {"top": {"lower": 3, "other": 9}}
        ]
    
        print(
            yaml.safe_dump(remove_matched_element("$..lower", spec)))
    

    上面的代码导致:

    [
        {
            "top": {
                "other": 1
            }
        },
        {
            "top": {
                "other": 4
            }
        },
        {
            "top": {
                "other": 9
            }
        }
    ]
    

    【讨论】:

      【解决方案2】:

      如果您知道架构已修复,则可以像这样简单地删除密钥

      l = [
        { "top": { "lower": 1, "other": 1 } },
        { "top": { "lower": 2, "other": 4 } },
        { "top": { "lower": 3, "other": 9 } }
      ]
      
      for d in l:
          del d["top"]["lower"]
      

      【讨论】:

      • 该架构在列表中是固定的,但在调用 remove_node_from_dict() 函数时未知。此外,要删除的节点仅在运行时给出。因此,代码需要通用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-02
      • 1970-01-01
      • 2019-04-12
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多