Как найти конкретное значение json по ключу?
Существует такой json:
{
"P1": "ss",
"Id": 1234,
"P2": {
"P1": "cccc"
},
"P3": [
{
"P1": "aaa"
}
]
}
Как я могу найти все значение P1
без его повторения всех json?
PS: P1
может быть где угодно в json.
Если ни один метод не может это сделать, можете ли вы рассказать мне, как выполнять итерацию через json?
Ответы
Ответ 1
Мой подход к этой проблеме будет другим.
Поскольку JSON не разрешает поиск по глубине сначала, переведите json в объект Python, передайте его в XML-декодер, а затем извлеките Node, который вы собираетесь искать
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']
Ответ 2
Как я уже сказал в своем другом ответе, я не думаю, что есть способ найти все значения, связанные с клавишей "P1"
, без перебора всей структуры. Однако я нашел еще лучший способ сделать то, что пришло мне в голову, глядя на @Mike Brennan ответ на другой вопрос, связанный с JSON Как получить строковые объекты вместо Unicode из 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']
Ответ 3
У меня была такая же проблема только на днях. Я запустил только поиск по всему объекту и учитывал как списки, так и 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, поэтому вам нужно будет выполнить json.loads перед тем, как передать его в deep_search.
Любые комментарии для оптимизации приветствуются!
Ответ 4
Преобразование 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
Использование 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)
Ответ 6
Принимая во внимание, что json - это просто строка, использование регулярных выражений с помощью look-ahead и look-behind может быстро выполнить эту задачу.
Как правило, 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
Я не думаю, что есть способ найти все значения, связанные с 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)
Ответ 8
Вы также можете использовать генератор для поиска объекта после json.load().
Пример кода из моего ответа здесь: fooobar.com/info/349755/...
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