有一个这样的 JSON:
{
"P1": "ss",
"Id": 1234,
"P2": {
"P1": "cccc"
},
"P3": [
{
"P1": "aaa"
}
]
}
如何在P1
不迭代所有 JSON 的情况下找到 all 的值?
PS:P1
可以在 JSON 中的任何位置。
如果没有方法可以做到这一点,你能告诉我如何遍历 JSON 吗?
正如我在另一个答案中所说,我认为没有一种方法可以在"P1"
不迭代整个结构的情况下找到与键关联的所有值。但是,在查看@Mike Brennan对另一个与 JSON 相关的问题的回答时,我想出了更好的方法来做到这一点。如何从 JSON 中获取字符串对象而不是 Unicode?
基本思想是使用仅接受的object_hook
参数json.loads()
来观察正在解码的内容并检查需要的值。
注意:这仅在表示为 JSON object
(即用花括号括 {}
起来的内容)时才有效,如您的示例中所示。
from __future__ import print_function
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))
(Python 3) 输出:
['cccc', 'aaa', 'ss']
前几天我也遇到了同样的问题。我最终只是搜索了整个对象并考虑了列表和字典。以下片段允许您搜索多个键的第一次出现。
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))
它返回一个字典,其中的键是搜索的键。Haystack 应该已经是一个 Python 对象了,所以你必须在将它传递给 deep_search 之前执行 json.loads。
欢迎大家提出优化意见!
我解决这个问题的方法会有所不同。
由于 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']
使用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)
将 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 是字符串)
示例代码忽略数组。添加它作为练习。
记住 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']
我认为没有任何方法可以在不遍历整个结构的情况下找到与 P1 相关的所有值。这是一种递归方式,首先将 JSON 对象反序列化为等效的 Python 对象。为了简化事情,大部分工作都是通过递归私有嵌套函数完成的。
import json
try:
STRING_TYPE = basestring
except NameError:
STRING_TYPE = str # Python 3
def find_values(id, obj):
results = []
def _find_values(id, obj):
try:
for key, value in obj.items(): # dict?
if key == id:
results.append(value)
elif not isinstance(value, STRING_TYPE):
_find_values(id, value)
except AttributeError:
pass
try:
for item in obj: # iterable?
if not isinstance(item, STRING_TYPE):
_find_values(id, item)
except TypeError:
pass
if not isinstance(obj, STRING_TYPE):
_find_values(id, obj)
return results
json_repr = '{"P1": "ss", "Id": 1234, "P2": {"P1": "cccc"}, "P3": [{"P1": "aaa"}]}'
obj = json.loads(json_repr)
print(find_values('P1', obj))
您还可以使用生成器在 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