有一个像这样的json:
{
"P1": "ss",
"Id": 1234,
"P2": {
"P1": "cccc"
},
"P3": [
{
"P1": "aaa"
}
]
}
如果不迭代所有json,我怎样才能找到所有P1
的值?
PS:P1
可以在json的任何地方。
如果没有方法可以做到这一点,你能告诉我如何遍历json吗?
答案 0 :(得分:18)
正如我在其他答案中所说,我认为没有办法找到与"P1"
键相关的所有值而不迭代整个结构。但是,我在考虑accepted answer到另一个问题How to get string objects instead of Unicode from JSON?
基本思想是使用object_hook
仅接受的json.loads()
参数来观察正在解码的内容并检查所追求的值。 注意:只有当表示形式为JSON Object
(即大括号{}
中包含的内容)时,此方法才有效,如示例json中所示。
import json
def find_values(id, json_repr):
results = []
def _decode_dict(a_dict):
try: results.append(a_dict[id])
except KeyError: pass
return a_dict
json.loads(json_repr, object_hook=_decode_dict) # Return value ignored.
return results
json_repr = '{"P1": "ss", "Id": 1234, "P2": {"P1": "cccc"}, "P3": [{"P1": "aaa"}]}'
print find_values('P1', json_repr)
输出:
[u'cccc', u'aaa', u'ss']
答案 1 :(得分:12)
前几天我遇到了同样的问题。我结束了搜索整个对象,并考虑了列表和dicts。以下代码段允许您搜索多个键的第一个出现。
import json
def deep_search(needles, haystack):
found = {}
if type(needles) != type([]):
needles = [needles]
if type(haystack) == type(dict()):
for needle in needles:
if needle in haystack.keys():
found[needle] = haystack[needle]
elif len(haystack.keys()) > 0:
for key in haystack.keys():
result = deep_search(needle, haystack[key])
if result:
for k, v in result.items():
found[k] = v
elif type(haystack) == type([]):
for node in haystack:
result = deep_search(needles, node)
if result:
for k, v in result.items():
found[k] = v
return found
deep_search(["P1", "P3"], json.loads(json_string))
它返回一个dict,键是搜索的键。 Haystack预计已经是一个Python对象了,所以在将它传递给deep_search之前你必须先做json.loads。
欢迎任何有关优化的评论!
答案 2 :(得分:10)
我解决这个问题的方法会有所不同。
由于JSON不允许深度优先搜索,因此将json转换为Python对象,将其提供给XML解码器,然后提取您要搜索的节点
from xml.dom.minidom import parseString
import json
def bar(somejson, key):
def val(node):
# Searches for the next Element Node containing Value
e = node.nextSibling
while e and e.nodeType != e.ELEMENT_NODE:
e = e.nextSibling
return (e.getElementsByTagName('string')[0].firstChild.nodeValue if e
else None)
# parse the JSON as XML
foo_dom = parseString(xmlrpclib.dumps((json.loads(somejson),)))
# and then search all the name tags which are P1's
# and use the val user function to get the value
return [val(node) for node in foo_dom.getElementsByTagName('name')
if node.firstChild.nodeValue in key]
bar(foo, 'P1')
[u'cccc', u'aaa', u'ss']
bar(foo, ('P1','P2'))
[u'cccc', u'cccc', u'aaa', u'ss']
答案 3 :(得分:7)
使用json
将json转换为Python对象,然后以递归方式进行最佳处理。此示例 包括浏览列表。
import json
def get_all(myjson, key):
if type(myjson) == str:
myjson = json.loads(myjson)
if type(myjson) is dict:
for jsonkey in myjson:
if type(myjson[jsonkey]) in (list, dict):
get_all(myjson[jsonkey], key)
elif jsonkey == key:
print myjson[jsonkey]
elif type(myjson) is list:
for item in myjson:
if type(item) in (list, dict):
get_all(item, key)
答案 4 :(得分:6)
将JSON转换为Python并递归搜索是最简单的:
def findall(v, k):
if type(v) == type({}):
for k1 in v:
if k1 == k:
print v[k1]
findall(v[k1], k)
findall(json.loads(a), 'P1')
(其中a是字符串)
示例代码忽略数组。添加它作为练习。
答案 5 :(得分:2)
我认为没有任何方法可以在不迭代整个结构的情况下找到与P1相关的所有值。这是一种递归方式,首先将文件中的json对象反序列化为等效的Python对象。为了简化操作,大部分工作都是通过私有嵌套函数完成的。
def find_values(id, obj):
results = []
def _find_values(id, obj):
try:
for key, value in obj.iteritems():
if key == id:
results.append(value)
elif not isinstance(value, basestring):
_find_values(id, value)
except AttributeError:
pass
try:
for item in obj:
if not isinstance(item, basestring):
_find_values(id, item)
except TypeError:
pass
if not isinstance(obj, basestring):
_find_values(id, obj)
return results
import json
with open('data.json') as json_file:
obj = json.load(json_file)
print find_values('P1', obj)
答案 6 :(得分:2)
请记住,json只是一个字符串,使用具有前瞻和后视的正则表达式可以非常快速地完成此任务。
通常情况下,json会从对外部api的请求中提取出来,所以代码显示了它是如何工作的,但已经被注释掉了。
import re
#import requests
#import json
#r1 = requests.get( ... url to some api ...)
#JSON = str(json.loads(r1.text))
JSON = """
{
"P1": "ss",
"Id": 1234,
"P2": {
"P1": "cccc"
},
"P3": [
{
"P1": "aaa"
}
]
}
"""
rex1 = re.compile('(?<=\"P1\": \")[a-zA-Z_\- ]+(?=\")')
rex2 = rex1.findall(JSON)
print(rex2)
#['ss', 'cccc', 'aaa']
答案 7 :(得分:1)
您还可以使用生成器在json.load()之后搜索对象。
我的回答中的代码示例:https://stackoverflow.com/a/39016088/5250939
def item_generator(json_input, lookup_key):
if isinstance(json_input, dict):
for k, v in json_input.iteritems():
if k == lookup_key:
yield v
else:
for child_val in item_generator(v, lookup_key):
yield child_val
elif isinstance(json_input, list):
for item in json_input:
for item_val in item_generator(item, lookup_key):
yield item_val