¿Cómo encontrar un valor json particular por clave?

Hay un json como este:

{ "P1": "ss", "Id": 1234, "P2": { "P1": "cccc" }, "P3": [ { "P1": "aaa" } ] } 

¿Cómo puedo encontrar todo el valor de P1 sin iterar todo json?

PS: P1 puede estar en cualquier lugar en json.

Si ningún método puede hacer esto, ¿puedes decirme cómo iterar a través del json?

Mi enfoque a este problema sería diferente.

Como JSON no permite una búsqueda profunda en profundidad, convierta el json en un objeto Python, aliméntelo a un decodificador XML y luego extraiga el nodo que desea buscar

 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'] 

Como dije en mi otra respuesta, no creo que haya una manera de encontrar todos los valores asociados con la tecla "P1" sin iterar en toda la estructura. Sin embargo, he encontrado una mejor manera de hacer lo que me vino a la vez que miraba la respuesta aceptada a una pregunta diferente ¿ Cómo obtener objetos de cadena en lugar de Unicode de JSON?

La idea básica es usar el parámetro object_hook que json.loads() acepta solo para observar lo que se está descodificando y verificar el valor buscado. Nota: Esto solo funcionará si la representación es de un Object JSON (es decir, algo encerrado entre llaves {} ), como en su muestra 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) 

Salida:

 [u'cccc', u'aaa', u'ss'] 

Tuve el mismo problema el otro día. Terminé simplemente buscando a través de todo el objeto y consideré tanto las listas como los dados. Los siguientes fragmentos de código le permiten buscar la primera aparición de varias claves.

 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)) 

Devuelve un dictado con las claves siendo las claves buscadas. Se espera que Haystack sea un objeto de Python, así que tienes que hacer json.loads antes de pasarlo a deep_search.

Cualquier comentario para la optimización son bienvenidos!

Usar json para convertir el json en objetos de Python y luego recursivamente funciona mejor. Este ejemplo no incluye ir a través de listas.

 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) 

Convertir el JSON en Python y buscar de forma recursiva es, con mucho, el más fácil:

 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') 

(donde a es la cadena)

El código de ejemplo ignora las matrices. Añadiendo que queda como ejercicio.

No creo que haya ninguna forma de encontrar todos los valores asociados con P1 sin iterar en toda la estructura. Aquí hay una forma recursiva de hacerlo que primero deserializa el objeto json en un archivo en un objeto Python equivalente. Para simplificar las cosas, la mayor parte del trabajo se realiza a través de una función anidada privada.

 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) 

Teniendo en cuenta que json es simplemente una cadena, el uso de expresiones regulares con look-ahead y look-behind puede realizar esta tarea muy rápidamente.

Por lo general, el json se habría extraído de una solicitud a una API externa, por lo que el código para mostrar cómo funcionaría se ha incluido pero se ha comentado.

 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'] 

También puede usar un generador para buscar el objeto después de json.load ().

Ejemplo de código de mi respuesta aquí: 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