是否有一种基于表达式的工具可以像使用XPath查询XML或jsonpath查询JSON那样查询Python复杂对象?
我考虑将我的对象序列化为JSON,然后在其上使用jsonpath,但这似乎是一种笨拙的方法。
json
将JSON导入为嵌套字典,并使用字典表示法遍历它- root['level1_object'] ['level2_object']
。 JSON兼容的对象类型当然会作为相应的Python类型加载。@vBobCat 我目前正在寻找类似的解决方案。同意使用json进行序列化和反序列化并不理想。你最终选择了什么?
我发现 http://objectpath.org/ 接近于我需要的正确解决方案,尽管它缺少我需要的对字段进行任意更新的功能。它的语法虽然与JSONPath略有不同,但表达了许多JSONPath的内容。
Box
库(在被接受的答案中)结合exec()
,这样我就可以在字符串中插入存储路径并执行它。 - VBobCat在这里添加一个非库选项。一种基于点符号字符串查找嵌套元素的方法(可以遍历嵌套的dicts
和lists
),请参见下面的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