当内部存在NULL值时,如何解析JSON?

时间:2019-09-02 15:58:17

标签: python json

我正在尝试解析JSON数据,但是当我在JSON的某些分支中具有NULL时,Python会给我一个错误: TypeError: 'NoneType' object is not subscriptable

这种情况还可以:

import json

x = '''[{"address":{"city": "city1","street": "street1"}},
        {"address":{"city": "city2","street": "street2"}}]'''
source = json.loads(x)
data = []
for s in source:
    data.append([s['address']['city'],
                 s['address']['street']])
print(data)

这给了我一个错误:

import json

x = '''[{"address":{"city": "city1","street": "street1"}},
        {"address": null},
        {"address":{"city": "city2","street": "street2"}}]'''
source = json.loads(x)
data = []
for s in source:
    data.append([s['address']['city'],
                 s['address']['street']])
print(data)

我想在第二种情况下获得NULL(无)值。最简单的方法是什么?

更新#1: 我还有很多其他数据,不仅是“地址”,而且其中任何一个也可以为NULL。这就是为什么我不能使用“ if语句”的原因(会有太多不同的组合)

更新#2: 为了使我的问题更清楚(实际上,我有25个不同的参数,而不是下面的3个):

[
    {
        "address": {
            "city": "city1",
            "street": "street1"
        },
        "car": null,
        "person": {
            "age": "30",
            "name": "John"
        }
    },
    {
        "address": null,
        "car": {
            "color": "red",
            "year": "2015"
        },
        "person": {
            "age": "31",
            "name": "Peter"
        }
    },
    {
        "address": {
            "city": "city2",
            "street": "street2"
        },
        "car": {
            "color": "green",
            "year": "2017"
        },
        "person": null
    }
]

    data.append(   [s['address']['city'],
                    s['address']['street'],
                    s['person']['name'],
                    s['paerson']['age'],
                    s['car']['year'],
                    s['car']['color']])

4 个答案:

答案 0 :(得分:2)

当您将JSON对象嵌套在一级深度且可能具有NULL值的情况下,这是一种处理情况的通用方法。它利用可选的object_hook=关键字参数将回调函数传递给json.loads()(与json.load()一样)。在这种情况下,函数会将上层None中的任何dict值转换为空的NoneDict字典子类实例。

NoneDict只需返回None作为丢失键的值,而不用引发KeyError。优化说明:如果您从不更改这些对象(即它们是只读的),则实际上只需要创建一个单独的全局实例,并始终在convertor()函数中使用它即可。

import json
from pprint import pprint


class NoneDict(dict):
    """ dict subclass that returns a value of None for missing keys instead
        of raising a KeyError. Note: doesn't add item to dictionary.
    """
    def __missing__(self, key):
        return None


def converter(decoded_dict):
    """ Convert any None values in decoded dict into empty NoneDict's. """
    return {k: NoneDict() if v is None else v for k,v in decoded_dict.items()}

# The following JSON data is equivalent to what you have in Update #2 of your
# question, it's just formatted more compactly.
x = '''
    [{"address": {"city": "city1", "street": "street1"},
      "car": null,
      "person": {"age": "30", "name": "John"}},
     {"address": null,
      "car": {"color": "red", "year": "2015"},
      "person": {"age": "31", "name": "Peter"}},
     {"address": {"city": "city2", "street": "street2"},
      "car": {"color": "green", "year": "2017"},
      "person": null}]
'''

source = json.loads(x, object_hook=converter)
data = []

for s in source:
    data.append([s['address']['city'],
                 s['address']['street'],
                 s['person']['name'],
                 s['person']['age'],
                 s['car']['year'],
                 s['car']['color']])

pprint(data)

输出:

[['city1', 'street1', 'John', '30', None, None],
 [None, None, 'Peter', '31', '2015', 'red'],
 ['city2', 'street2', None, None, '2017', 'green']]

请注意,可以将末端附近的部分写成这样,以使其更“受数据驱动”:

items = (('address', 'city'),
         ('address', 'street'),
         ('person', 'name'),
         ('person', 'age'),
         ('car', 'year'),
         ('car', 'color'))

for s in source:
    data.append([s[k1][k2] for k1, k2 in items])

答案 1 :(得分:1)

分别处理None情况:

for s in source:
    address = s['address']

    data.append(
       [None, None] if address is None
       else [address['city'], address['street']]
    )

答案 2 :(得分:1)

您必须先检查地址是否为空,然后再尝试从中访问内容。 例如:

for s in source:
    if s['address']:
        data.append([s['address']['city]',s['address']['street']])
    else:
        # whatever behaviour you want for None values

答案 3 :(得分:1)

问题在于,在第二种情况下,s ['address']的计算结果为无,并且无法下标。您应检查该值是否不是None并分别处理这种情况:

import json

x = '''[{"address":{"city": "city1","street": "street1"}},
        {"address": null},
        {"address":{"city": "city2","street": "street2"}}]'''                          
source = json.loads(x)
data = []
for s in source:
    if s['address'] is not None:
        data.append([s['address']['city'],
                     s['address']['street']])
    else:
        data.append(None)
print(data)

这将打印:[['city1', 'street1'], None, ['city2', 'street2']]

编辑: 试试这个:

import pandas as pd
df = pd.io.json.json_normalize(source)
df = df.where((pd.notnull(df)), None)
data = df[[column for column in df.columns if '.' in column]]
print(data.values.tolist())

输出: [['city1','street1',无,无,'30','约翰'],[无,无,'红色','2015','31','彼得'],['city2', 'street2','green','2017',无,无]]