Python 如何按键查找特定的 json 值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14048948/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to find a particular json value by key?
提问by lichengwu
There is a json like this:
有一个这样的json:
{
"P1": "ss",
"Id": 1234,
"P2": {
"P1": "cccc"
},
"P3": [
{
"P1": "aaa"
}
]
}
How can I find all P1's value without it iterating all json?
如何在P1不迭代所有 json 的情况下找到 all的值?
PS:P1can be anywhere in json.
PS:P1可以在json中的任何地方。
If no method can do this, can you tell me how to iterate through the json?
如果没有方法可以做到这一点,你能告诉我如何遍历json吗?
采纳答案by Abhijit
My approach to this problem would be different.
我对这个问题的处理方法会有所不同。
As JSON doesn't allow depth first search, so convert the json to a Python Object, feed it to an XML decoder and then extract the Node you are intending to search
由于 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']
回答by Malvolio
Converting the JSON to Python and recursively searching is by far the easiest:
将 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')
(where a is the string)
(其中 a 是字符串)
The example code ignores arrays. Adding that is left as an exercise.
示例代码忽略数组。添加它作为练习。
回答by jdotjdot
Using jsonto convert the json to Python objects and then going through recursively works best. This example doesinclude going through lists.
使用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)
回答by Sean Linehan
I had the same issue just the other day. I wound up just searching through the entire object and accounted for both lists and dicts. The following snippets allows you to search for the firstoccurrence of a multiple keys.
前几天我遇到了同样的问题。我最终只是搜索了整个对象并考虑了列表和字典。以下片段允许您搜索多个键的第一次出现。
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))
It returns a dict with the keys being the keys searched for. Haystack is expected to be a Python object already, so you have to do json.loads before passing it to deep_search.
它返回一个字典,其中的键是搜索的键。Haystack 应该已经是一个 Python 对象,所以你必须在将它传递给 deep_search 之前执行 json.loads。
Any comments for optimization are welcomed!
欢迎任何优化意见!
回答by martineau
I don't think there's any way of finding all values associated with P1 without iterating over the whole structure. Here's a recursive way to do it that first deserializes the json object in a file into an equivalent Python object. To simplify things most of the work is done via a private nested function.
我认为没有任何方法可以在不迭代整个结构的情况下找到与 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)
回答by martineau
As I said in my other answer, I don't think there is a way of finding all values associated with the "P1"key without iterating over the whole structure. However I've come up with even better way to do that which came to me while looking at @Mike Brennan's answerto another JSON-related question How to get string objects instead of Unicode from JSON?
正如我在其他答案中所说,我认为没有一种方法可以在"P1"不遍历整个结构的情况下找到与键关联的所有值。不过我已经想出更好的方法来做到这一点它来找我一边看着@Mike布伦南的回答另一个JSON相关的问题,如何获得字符串从JSON对象,而不是Unicode的?
The basic idea is to use the object_hookparameter that json.loads()accepts just to watch what is being decoded and check for the sought-after value.
基本思想是使用接受的object_hook参数json.loads()来观察正在解码的内容并检查寻求值。
Note:This will only work if the representation is of a JSON object(i.e. something enclosed in curly braces {}), as in your sample json.
注意:这仅在表示是 JSON object(即括在花括号中的内容{})时才有效,如示例 json 中所示。
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 2) output:
(Python 2)输出:
[u'cccc', u'aaa', u'ss']
回答by Bo Sunesen
You could also use a generator to search the object after json.load().
您还可以使用生成器在 json.load() 之后搜索对象。
Code example from my answer here: https://stackoverflow.com/a/39016088/5250939
我在此处回答的代码示例: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
回答by Tony Mobbs
Bearing in mind that json is simply a string, using regular expressions with look-ahead and look-behind can accomplish this task very quickly.
记住 json 只是一个字符串,使用带有前瞻和后视的正则表达式可以非常快速地完成这项任务。
Typically, the json would have been extracted from a request to external api, so code to show how that would work has been included but commented out.
通常,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']

