次のような JSON があります。
{
"P1": "ss",
"Id": 1234,
"P2": {
"P1": "cccc"
},
"P3": [
{
"P1": "aaa"
}
]
}
P1
すべての JSON を反復せずにall の値を見つけるにはどうすればよいですか?
PS: JSON のどこP1
にでもかまいません。
これを行う方法がない場合、JSON を反復処理する方法を教えてもらえますか?
他の回答で述べたように"P1"
、構造全体を反復せずにキーに関連付けられたすべての値を見つける方法はないと思います。ただし、別のJSON関連の質問How to get string objects instead of Unicode from JSON?
基本的な考え方は、デコードされているものを監視し、求められている値を確認するためだけに受け入れる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))
キーが検索対象のキーである dict を返します。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.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