Compruebe si existe la clave e itere la matriz JSON usando Python

130

Tengo un montón de datos JSON de publicaciones de Facebook como el siguiente:

{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}

Los datos JSON están semiestructurados y no todo es lo mismo. Debajo está mi código:

import json 

str = '{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}'
data = json.loads(str)

post_id = data['id']
post_type = data['type']
print(post_id)
print(post_type)

created_time = data['created_time']
updated_time = data['updated_time']
print(created_time)
print(updated_time)

if data.get('application'):
    app_id = data['application'].get('id', 0)
    print(app_id)
else:
    print('null')

#if data.get('to'):
#... This is the part I am not sure how to do
# Since it is in the form "to": {"data":[{"id":...}]}

Quiero que el código imprima to_id como 1543 más imprima 'nulo'

No estoy seguro de cómo hacer esto.

pravi
fuente

Respuestas:

162
import json

jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    if 'to' not in data:
        raise ValueError("No target in given data")
    if 'data' not in data['to']:
        raise ValueError("No data for target")

    for dest in data['to']['data']:
        if 'id' not in dest:
            continue
        targetId = dest['id']
        print("to_id:", targetId)

Salida:

In [9]: getTargetIds(s)
to_id: 1543
inspectorG4dget
fuente
66
¿Por qué esto inverifica explícitamente y raisesi faltan? Simplemente acceda a él sin verificar, y obtendrá exactamente el mismo comportamiento (excepto con un en KeyErrorlugar de un ValueError).
abarnert
101

Si todo lo que quiere es verificar si la clave existe o no

h = {'a': 1}
'b' in h # returns False

Si desea verificar si hay un valor para la clave

h.get('b') # returns None

Devuelve un valor predeterminado si falta el valor real

h.get('b', 'Default value')
athap
fuente
devolverá 'nulo' y no 'Valor predeterminado' como se esperaba para b en caso de {'a': 1, 'b': nulo}
MikeL
16

Es una buena práctica crear métodos de utilidad auxiliar para cosas como esas, de modo que siempre que necesite cambiar la lógica de validación de atributos esté en un solo lugar, y el código sea más legible para los seguidores.

Por ejemplo, cree un método auxiliar (o una clase JsonUtilscon métodos estáticos) en json_utils.py:

def get_attribute(data, attribute, default_value):
    return data.get(attribute) or default_value

y luego úsalo en tu proyecto:

from json_utils import get_attribute

def my_cool_iteration_func(data):

    data_to = get_attribute(data, 'to', None)
    if not data_to:
        return

    data_to_data = get_attribute(data_to, 'data', [])
    for item in data_to_data:
        print('The id is: %s' % get_attribute(item, 'id', 'null'))

NOTA IMPORTANTE:

Hay una razón por la que estoy usando en data.get(attribute) or default_valuelugar de simplemente data.get(attribute, default_value):

{'my_key': None}.get('my_key', 'nothing') # returns None
{'my_key': None}.get('my_key') or 'nothing' # returns 'nothing'

En mis aplicaciones, obtener el atributo con el valor 'nulo' es lo mismo que no obtener el atributo en absoluto. Si su uso es diferente, debe cambiar esto.

MikeL
fuente
4
jsonData = """{"from": {"id": "8", "name": "Mary Pinter"}, "message": "How ARE you?", "comments": {"count": 0}, "updated_time": "2012-05-01", "created_time": "2012-05-01", "to": {"data": [{"id": "1543", "name": "Honey Pinter"}, {"name": "Joe Schmoe"}]}, "type": "status", "id": "id_7"}"""

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        print("to_id:", dest.get('id', 'null'))

Intentalo:

>>> getTargetIds(jsonData)
to_id: 1543
to_id: null

O, si solo desea omitir los valores que faltan identificadores en lugar de imprimir 'null':

def getTargetIds(jsonData):
    data = json.loads(jsonData)
    for dest in data['to']['data']:
        if 'id' in to_id:
            print("to_id:", dest['id'])

Entonces:

>>> getTargetIds(jsonData)
to_id: 1543

Por supuesto, en la vida real, probablemente no desee printcada identificación, sino almacenarlas y hacer algo con ellas, pero ese es otro problema.

abarnert
fuente
4
if "my_data" in my_json_data:
         print json.dumps(my_json_data["my_data"])
Ajit Surendran
fuente
4

Escribí una pequeña función para este propósito. Siéntase libre de reutilizar,

def is_json_key_present(json, key):
    try:
        buf = json[key]
    except KeyError:
        return False

    return True
tabdiukov
fuente