Python对象遍历的路径语法

4

是否有一种基于表达式的工具可以像使用XPath查询XML或jsonpath查询JSON那样查询Python复杂对象?

我考虑将我的对象序列化为JSON,然后在其上使用jsonpath,但这似乎是一种笨拙的方法。


“复杂对象”是什么意思?嵌套字典吗? - Carcigenicate
我的意思是像JSON对象一样复杂的东西:可遍历的元素树,可以是bool、str、int、float,也可以是dict(作为对象)和list(作为数组)。但根元素确实是一个字典。 - VBobCat
5个回答

2
您可以使用内置库json将JSON导入为嵌套字典,并使用字典表示法遍历它- root['level1_object'] ['level2_object'] 。 JSON兼容的对象类型当然会作为相应的Python类型加载。
对于其他类型的数据,有其他库,它们大多以类似的方式运行。
我最喜欢的新库是Box,它允许您使用点符号遍历嵌套字典。

Box看起来很有前途,我会去了解一下。 - VBobCat

1

我为了未来的研究者而添加这个答案:

看起来jsonpath-rw是我一直在寻找的库,因为它正好做到了我最初的要求。


1

@vBobCat 我目前正在寻找类似的解决方案。同意使用json进行序列化和反序列化并不理想。你最终选择了什么?

我发现 http://objectpath.org/ 接近于我需要的正确解决方案,尽管它缺少我需要的对字段进行任意更新的功能。它的语法虽然与JSONPath略有不同,但表达了许多JSONPath的内容。


1
你好,抱歉回复晚了。我的用例足够简单,所以我使用了Box库(在被接受的答案中)结合exec(),这样我就可以在字符串中插入存储路径并执行它。 - VBobCat
1
你好,我不知道经过这么长时间后它是否仍对你有用,实际上 jsonpath-rw 似乎是我们一直在寻找的库。 - VBobCat
嘿@VBobCat,糟糕了,我没有想到更新这个,但是是的,我得出了和你一样的结论。最初我假设该库需要一个json字符串作为输入,但事实证明这是不正确的,你可以传递字典和列表。 - Greg

1

你如何使用AST查询“复杂对象”? - Maurice Meyer
我可能误解了,但似乎我需要将我的根字典序列化为字符串才能使用它。我错过了什么吗? - VBobCat

0

在这里添加一个非库选项。一种基于点符号字符串查找嵌套元素的方法(可以遍历嵌套的dictslists),请参见下面的Gist here

from functools import reduce
import re
from typing import Any, Optional

def find_key(dot_notation_path: str, payload: dict) -> Any:
    """Try to get a deep value from a dict based on a dot-notation"""

    def get_despite_none(payload: Optional[dict], key: str) -> Any:
        """Try to get value from dict, even if dict is None"""
        if not payload or not isinstance(payload, (dict, list)):
            return None
        # can also access lists if needed, e.g., if key is '[1]'
        if (num_key := re.match(r"^\[(\d+)\]$", key)) is not None:
            try:
                return payload[int(num_key.group(1))]
            except IndexError:
                return None
        else:
            return payload.get(key, None)

    found = reduce(get_despite_none, dot_notation_path.split("."), payload)
   
    # compare to None, as the key could exist and be empty
    if found is None:
        raise KeyError()
    return found

# Test cases:

payload = {
    "haystack1": {
        "haystack2": {
            "haystack3": None, 
            "haystack4": "needle"
        }
    },
    "haystack5": [
        {"haystack6": None}, 
        {"haystack7": "needle"}
    ],
    "haystack8": {},
}

find_key("haystack1.haystack2.haystack4", payload)
# "needle"
find_key("haystack5.[1].haystack7", payload)
# "needle"
find_key("[0].haystack5.[1].haystack7", [payload, None])
# "needle"
find_key("haystack8", payload)
# {}
find_key("haystack1.haystack2.haystack4.haystack99", payload)
# KeyError

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接