将嵌套的JSON(Dict,List)嵌入到列表中以准备写入DB [英] Flatten nested JSON (Dict, List) into List to prepare to write into DB

查看:96
本文介绍了将嵌套的JSON(Dict,List)嵌入到列表中以准备写入DB的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我仍在努力解决一个嵌套的JSON文件的问题。嵌套的项目是列表或Dict:

I am still working on a problem to flatten a nested JSON file. The nested items are either List or Dict:

这是我要展平的文件(不像以前的帖子,我保持它很好,但它只包含输入[0]不是任何后续项目,因为它将很长):

Here is the file I want to flatten (Unlike in my previous post, I kept it at good length, but it only contains input[0] not any subsequent items as it will be very long):

input = [{'states': ['USED'], 'niceName': '1-series', 'id': 'BMW_1_Series',
            'years': [{'styles':
                       [{'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'},
                         'name': '128i 2dr Convertible (3.0L 6cyl 6M)', 'id': 100994560},
                        {'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'},
                          'name': '128i 2dr Coupe (3.0L 6cyl 6M)', 'id': 100974974},
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '135i 2dr Coupe (3.0L 6cyl Turbo 6M)', 'id': 100974975},
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '135i 2dr Convertible (3.0L 6cyl Turbo 6M)', 'id': 100994561}
                        ],
                       'states': ['USED'], 'id': 100524709, 'year': 2008},
                      {'styles':
                       [{'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '135i 2dr Coupe (3.0L 6cyl Turbo 6M)', 'id': 101082656}, 
                        {'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '128i 2dr Coupe (3.0L 6cyl 6M)', 'id': 101082655},
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '135i 2dr Convertible (3.0L 6cyl Turbo 6M)', 'id': 101082663},
                        {'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '128i 2dr Convertible (3.0L 6cyl 6M)', 'id': 101082662}
                        ], 
                       'states': ['USED'], 'id': 100503222, 'year': 2009},
                      {'styles': 
                       [{'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '128i 2dr Coupe (3.0L 6cyl 6M)', 'id': 101200599},
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '135i 2dr Coupe (3.0L 6cyl Turbo 6M)', 'id': 101200600}, 
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '135i 2dr Convertible (3.0L 6cyl Turbo 6M)', 'id': 101200607}, 
                        {'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '128i 2dr Convertible (3.0L 6cyl 6M)', 'id': 101200601}
                        ], 
                       'states': ['USED'], 'id': 100529091, 'year': 2010}, 
                      {'styles':
                       [{'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '128i 2dr Coupe (3.0L 6cyl 6M)', 'id': 101288165}, 
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '135i 2dr Coupe (3.0L 6cyl Turbo 6M)', 'id': 101288166}, 
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '135i 2dr Convertible (3.0L 6cyl Turbo 6M)', 'id': 101288298}, 
                        {'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '128i 2dr Convertible (3.0L 6cyl 6M)', 'id': 101288297}
                        ], 
                       'states': ['USED'], 'id': 100531309, 'year': 2011}, 
                      {'styles': 
                       [{'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '128i 2dr Convertible (3.0L 6cyl 6M)', 'id': 101381667}, 
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '135i 2dr Convertible (3.0L 6cyl Turbo 6M)', 'id': 101381668}, 
                        {'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '128i 2dr Coupe (3.0L 6cyl 6M)', 'id': 101381665}, 
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '135i 2dr Coupe (3.0L 6cyl Turbo 6M)', 'id': 101381666}
                        ], 
                       'states': ['USED'], 'id': 100534729, 'year': 2012}, 
                      {'styles': 
                       [{'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                        'name': '128i 2dr Coupe (3.0L 6cyl 6M)', 'id': 200428722},
                        {'trim': '128i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '128i 2dr Convertible (3.0L 6cyl 6M)', 'id': 200428721}, 
                        {'trim': '135is', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '135is 2dr Coupe (3.0L 6cyl Turbo 6M)', 'id': 200421701}, 
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '135i 2dr Coupe (3.0L 6cyl Turbo 6M)', 'id': 200428724}, 
                        {'trim': '135i', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '135i 2dr Convertible (3.0L 6cyl Turbo 6M)', 'id': 200428723}, 
                        {'trim': '128i SULEV', 'states': ['USED'], 'submodel': {'body': 'Coupe', 'niceName': 'coupe', 'modelName': '1 Series Coupe'}, 
                         'name': '128i SULEV 2dr Coupe (3.0L 6cyl 6M)', 'id': 200428726}, 
                        {'trim': '128i SULEV', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '128i SULEV 2dr Convertible (3.0L 6cyl 6M)', 'id': 200428725}, 
                        {'trim': '135is', 'states': ['USED'], 'submodel': {'body': 'Convertible', 'niceName': 'convertible', 'modelName': '1 Series Convertible'}, 
                         'name': '135is 2dr Convertible (3.0L 6cyl Turbo 6M)', 'id': 200428727}
                        ], 
                       'states': ['USED'], 'id': 200421700, 'year': 2013}
                      ], 
          'name': '1 Series', 'make': {'niceName': 'bmw', 'name': 'BMW', 'id': 200000081}
          }, #here is more to come, but I needed to crop it
          ]

我的aproach失败后使用的代码是由@poke由:在Python中修改Python或Dists列表中的通用JSON列表


The code I used so far after failing with my aproach was written by @poke from: Flattening Generic JSON List of Dicts or Lists in Python

def splitObj (obj, prefix = None):
    '''
    Split the object, returning a 3-tuple with the flat object, optionally
    followed by the key for the subobjects and a list of those subobjects.
    '''
    # copy the object, optionally add the prefix before each key
    new = obj.copy() if prefix is None else { '{}_{}'.format(prefix, k): v for k, v in obj.items() }

    # try to find the key holding the subobject or a list of subobjects
    for k, v in new.items():
        # list of subobjects
        if isinstance(v, list):
            del new[k]
            return new, k, v
        # or just one subobject
        elif isinstance(v, dict):
            del new[k]
            return new, k, [v]
    return new, None, None

def flatten (data, prefix = None):
    '''
    Flatten the data, optionally with each key prefixed.
    '''
    # iterate all items
    for item in data:
        # split the object
        flat, key, subs = splitObj(item, prefix)

        # just return fully flat objects
        if key is None:
            yield flat
            continue

        # otherwise recursively flatten the subobjects
        for sub in flatten(subs, key):
            sub.update(flat)
            yield sub

我收到以下错误:

AttributeError: 'str' object has no attribute 'items'

哪些结果来自'states':['USED']

我不知道如何处理。关键的状态可以保留为列表。

I do not know how to handle that. The key 'states' can be kept as a list.

我希望有人能帮助我。

Ps:这是从 Python:将嵌套JSON写入列表中的多个元素

推荐答案

这是我的解决方案split obj

Here is my solution for splitObj

def splitObj (obj, prefix = None):
'''
Split the object, returning a 3-tuple with the flat object, optionally
followed by the key for the subobjects and a list of those subobjects.
obj needs to be a Dictonary
'''
# copy the object, optionally add the prefix before each key
new = obj.copy() if prefix is None or prefix=="NotFlat" else { '{}_{}'.format(prefix, k): v for k, v in obj.items() }

cL = 0
cD = 0
# try to find the key holding the subobject or a list of subobjects
for k, v in new.items():
    #Determine the number of lists in v
    if isinstance(v, list):
        cL += 1
    #Determine the number of dict in v
    elif isinstance(v, dict):
        cD += 1     
for k, v in new.items():
    # list of subobjects
    if isinstance(v, list):
        if (cD+cL) <=1:
            try:
                type(v[0])
            except IndexError:
                v = [""]
            if not isinstance(v[0], str):
                del new[k]
                return new, k, v
            elif isinstance(v[0], str):
                #handle list when only containing strings, return, the whole thing
                #solve other dicts which might be in the line
                #use "NotFlat" to run loop again but without adding a prefix

                new[k] = ", ".join(v)
                return new, None, None
            else:
                custLog.logger.info("")
        elif (cD+cL) >1:

            #print("Count List2 CD: "+str(cD))
            #print("Count LIST2 CL: "+str(cL))

            #if list is empty
            try:
                type(v[0])
            except IndexError:
                v = [""]

            if not isinstance(v[0], str):
                del new[k]
                for x in flatten([new]):
                    newOut = x
                    break
                return newOut, k, v
            elif isinstance(v[0], str):
                #handle list when only containing strings, return, the whole thing
                #solve other dicts which might be in the line
                #use "NotFlat" to run loop again but without adding a prefix
                new[k] = ", ".join(v)
                return None, "NotFlat", [new]
            else:
                custLog.logger.error("weder noch 2")

    # or just one subobject
    elif isinstance(v, dict):
        if (cD+cL) <=1:
            del new[k]
            return new, k, [v]
        elif (cD+cL) >1:
            del new[k]
            for x in flatten([new]):
                newOut = x
                break
            return newOut, k, [v]
return new, None, None

,这里为扁平化

def flatten (data, prefix = None):
'''
Flatten the data, optionally with each key prefixed.
'''
# iterate all items


for item in data:
    # split the object
    flat, key, subs = splitObj(item, prefix)
    if subs is None:
        if key is None:
            yield flat
            continue    
    # just return fully flat objects
    if key is None and flat is not None:
        yield flat
        continue

    # otherwise recursively flatten the subobjects
    try:
        for sub in flatten(subs, key):
            if flat is not None:
                sub.update(flat)
            yield sub
    except TypeError as e:
        custLog.logger.error("ERR: TypeError"+str(e))

这篇关于将嵌套的JSON(Dict,List)嵌入到列表中以准备写入DB的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆