Periksa apakah kunci ada dan lakukan iterasi array JSON menggunakan Python

130

Saya memiliki banyak data JSON dari pos-pos Facebook seperti di bawah ini:

{"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 bersifat semi-terstruktur dan semuanya tidak sama. Di bawah ini adalah kode saya:

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":...}]}

Saya ingin kode untuk mencetak to_id sebagai 1543 lagi cetak 'nol'

Saya tidak yakin bagaimana melakukan ini.

pravi
sumber

Jawaban:

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)

Keluaran:

In [9]: getTargetIds(s)
to_id: 1543
inspectorG4dget
sumber
6
Mengapa ini secara eksplisit inmemeriksa dan raisejika mereka hilang? Akses saja tanpa memeriksa, dan Anda akan mendapatkan perilaku yang persis sama (kecuali dengan KeyErrorbukannya a ValueError).
abarnert
101

Jika semua yang Anda inginkan adalah untuk memeriksa apakah kunci ada atau tidak

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

Jika Anda ingin memeriksa apakah ada nilai untuk kunci

h.get('b') # returns None

Kembalikan nilai default jika nilai aktual tidak ada

h.get('b', 'Default value')
athap
sumber
akan mengembalikan 'nol' dan bukan 'Nilai default' seperti yang diharapkan untuk b jika {'a': 1, 'b': null}
MikeL
16

Ini adalah praktik yang baik untuk membuat metode utilitas pembantu untuk hal-hal seperti itu sehingga setiap kali Anda perlu mengubah logika validasi atribut, itu akan berada di satu tempat, dan kode tersebut akan lebih mudah dibaca oleh pengikut.

Misalnya membuat metode pembantu (atau kelas JsonUtilsdengan metode statis) di json_utils.py:

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

dan kemudian menggunakannya dalam proyek Anda:

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

CATATAN PENTING:

Ada alasan mengapa saya menggunakan data.get(attribute) or default_valuebukan hanya data.get(attribute, default_value):

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

Dalam aplikasi saya mendapatkan atribut dengan nilai 'null' sama dengan tidak mendapatkan atribut sama sekali. Jika penggunaan Anda berbeda, Anda perlu mengubahnya.

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

Cobalah:

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

Atau, jika Anda hanya ingin melewatkan nilai id yang hilang alih-alih mencetak 'null':

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

Begitu:

>>> getTargetIds(jsonData)
to_id: 1543

Tentu saja dalam kehidupan nyata, Anda mungkin tidak ingin printsetiap id, tetapi untuk menyimpannya dan melakukan sesuatu dengan mereka, tapi itu masalah lain.

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

Saya menulis fungsi kecil untuk tujuan ini. Merasa bebas untuk digunakan kembali,

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

    return True
tabdiukov
sumber