有没有办法为嵌套的python词典定义XPath类型查询。
这样的事情:
foo = {
'spam':'eggs',
'morefoo': {
'bar':'soap',
'morebar': {'bacon' : 'foobar'}
}
}
print( foo.select("/morefoo/morebar") )
>> {'bacon' : 'foobar'}
我还需要选择嵌套列表;)
这可以通过@ jellybean的解决方案轻松完成:
def xpath_get(mydict, path):
elem = mydict
try:
for x in path.strip("/").split("/"):
try:
x = int(x)
elem = elem[x]
except ValueError:
elem = elem.get(x)
except:
pass
return elem
foo = {
'spam':'eggs',
'morefoo': [{
'bar':'soap',
'morebar': {
'bacon' : {
'bla':'balbla'
}
}
},
'bla'
]
}
print xpath_get(foo, "/morefoo/0/morebar/bacon")
[编辑2016]这个问题和接受的答案是古老的。较新的答案可能比原始答案更好地完成工作。但是我没有测试它们所以我不会改变接受的答案。
答案 0 :(得分:19)
我能够识别的最好的库之一,此外,它是非常积极开发的,是boto提取的项目:JMESPath。它有一个非常强大的做法语法,通常需要用代码页来表达。
以下是一些例子:
search('foo | bar', {"foo": {"bar": "baz"}}) -> "baz"
search('foo[*].bar | [0]', {
"foo": [{"bar": ["first1", "second1"]},
{"bar": ["first2", "second2"]}]}) -> ["first1", "second1"]
search('foo | [0]', {"foo": [0, 1, 2]}) -> [0]
答案 1 :(得分:12)
现在有一种更简单的方法可以做到这一点。
http://github.com/akesterson/dpath-python
$ easy_install dpath
>>> dpath.util.search(YOUR_DICTIONARY, "morefoo/morebar")
......完成了。或者,如果您不希望将结果返回到视图中(保留路径的合并字典),请改为生成它们:
$ easy_install dpath
>>> for (path, value) in dpath.util.search(YOUR_DICTIONARY, "morefoo/morebar", yielded=True)
......完成了。在这种情况下,'价值'将保持{'培根':'foobar'}。
答案 2 :(得分:12)
有更新的jsonpath-rw库支持JSONPATH语法,但对于python 词典和数组,正如您所希望的那样。
所以你的第一个例子变成了:
from jsonpath_rw import parse
print( parse('$.morefoo.morebar').find(foo) )
第二名:
print( parse("$.morefoo[0].morebar.bacon").find(foo) )
PS:支持字典的另一个更简单的库是python-json-pointer,它具有更多类似XPath的语法。
答案 3 :(得分:10)
不完全漂亮,但你可能会像......一样使用
def xpath_get(mydict, path):
elem = mydict
try:
for x in path.strip("/").split("/"):
elem = elem.get(x)
except:
pass
return elem
这不支持像路径这样的xpath内容,当然......更不用说/
关键陷阱unutbu指示。
答案 4 :(得分:3)
如果简洁是你的幻想:
def xpath(root, path, sch='/'):
return reduce(lambda acc, nxt: acc[nxt],
[int(x) if x.isdigit() else x for x in path.split(sch)],
root)
当然,如果你只有有dicts,那么它更简单:
def xpath(root, path, sch='/'):
return reduce(lambda acc, nxt: acc[nxt],
path.split(sch),
root)
祝您在路径规格中发现任何错误; - )
答案 5 :(得分:1)
更多的工作必须放在类似XPath的选择器如何工作。
'/'
是一个有效的字典键,所以如何
foo={'/':{'/':'eggs'},'//':'ham'}
被处理?
foo.select("///")
会含糊不清。
答案 6 :(得分:1)
你是否有任何理由像XPath模式那样查询它?正如您的问题的评论者所建议的那样,它只是一个字典,因此您可以以嵌套的方式访问元素。此外,考虑到数据采用JSON格式,您可以使用simplejson模块加载它并访问元素。
有一个项目JSONPATH,它试图帮助人们做你想要做的事情(给定一个XPATH,如何通过python对象轻松访问它),这似乎更有用。
答案 7 :(得分:1)
另一个替代方案(除jellybean建议之外)是:
def querydict(d, q):
keys = q.split('/')
nd = d
for k in keys:
if k == '':
continue
if k in nd:
nd = nd[k]
else:
return None
return nd
foo = {
'spam':'eggs',
'morefoo': {
'bar':'soap',
'morebar': {'bacon' : 'foobar'}
}
}
print querydict(foo, "/morefoo/morebar")
答案 8 :(得分:0)
您可以使用JMESPath,它是JSON的查询语言,并且具有python implementation。
import jmespath # pip install jmespath
data = {'root': {'section': {'item1': 'value1', 'item2': 'value2'}}}
jmespath.search('root.section.item2', data)
Out[42]: 'value2'
jmespath查询语法和实时示例:http://jmespath.org/tutorial.html
另一种选择是使用dicttoxml之类的方法将字典转换为XML,然后使用正则XPath表达式,例如通过lxml或您喜欢的任何其他库。
from dicttoxml import dicttoxml # pip install dicttoxml
from lxml import etree # pip install lxml
data = {'root': {'section': {'item1': 'value1', 'item2': 'value2'}}}
xml_data = dicttoxml(data, attr_type=False)
Out[43]: b'<?xml version="1.0" encoding="UTF-8" ?><root><root><section><item1>value1</item1><item2>value2</item2></section></root></root>'
tree = etree.fromstring(xml_data)
tree.xpath('//item2/text()')
Out[44]: ['value2']
答案 9 :(得分:0)
def Dict(var, *arg, **kwarg):
""" Return the value of an (imbricated) dictionnary, if all fields exist else return "" unless "default=new_value" specified as end argument
Avoid TypeError: argument of type 'NoneType' is not iterable
Ex: Dict(variable_dict, 'field1', 'field2', default = 0)
"""
for key in arg:
if isinstance(var, dict) and key and key in var: var = var[key]
else: return kwarg['default'] if kwarg and 'default' in kwarg else "" # Allow Dict(var, tvdbid).isdigit() for example
return kwarg['default'] if var in (None, '', 'N/A', 'null') and kwarg and 'default' in kwarg else "" if var in (None, '', 'N/A', 'null') else var
foo = {
'spam':'eggs',
'morefoo': {
'bar':'soap',
'morebar': {'bacon' : 'foobar'}
}
}
print Dict(foo, 'morefoo', 'morebar')
print Dict(foo, 'morefoo', 'morebar', default=None)
具有SaveDict(value,var,* arg)函数,该函数甚至可以追加到字典中的列表...