Retreiving multiple data from json without knowing data type?

Viewed 38

Complete noob in python here, I'm trying to retrieve some values from a JSON response and I'm facing a 'str' object has no attribute error I don't work around, it seems because what I retrieve changes types.

Here is the json stored in "response":

{
"root": {
    "id": "683308188000",
    "type1": {
        "type1_1": {
            "id": "683308185000",
            "sub_info1": {
                "sub_info1_1": {
                    "name": "thing"
                }
            }
        }
    },
    "multiType_1": {
        "multiType_1_1": [
            {
                "id": "24567876543456",
                "name": {
                    "name2": {
                        "name": "grerggre"
                    }
                }
            },
            {
                "id": "234567654334",
                "name": {
                    "name2": {
                        "name": "grerggre"
                    }
                }
            }
        ]
    },
    "multiType_2": {
        "multiType_2_2": {
            "id": "683308570000",
                "name": {
                    "name2": {
                        "name": "grerggre"
                    }
                }
            }
        }
    }
}

Now here my code to retrieve all id :

result1 = []
result2 = []
for x in response.root.multiType1.multiType1_1:
    result1.append(x.id)
for x in response.root.multiType2.multiType2_2:
    result2.append(x.id)

result1 works, but for result2 I get a 'str' object has no attribute error. I can get the value in this specific case via response.root.multiType2.multiType2_2.id, but I don't know in advance I there will be one or multiple occurrences of each "multiType".

Is there a way to get around this ? Many thanks.

2 Answers

You need a recursive approach that can also handle lists. Something like this:

data = {
    "root": {
        "id": "683308188000",
        "type1": {
            "type1_1": {
                "id": "683308185000",
                "sub_info1": {
                    "sub_info1_1": {
                        "name": "thing"
                    }
                }
            }
        },
        "multiType_1": {
            "multiType_1_1": [
                {
                    "id": "24567876543456",
                    "name": {
                        "name2": {
                            "name": "grerggre"
                        }
                    }
                },
                {
                    "id": "234567654334",
                    "name": {
                        "name2": {
                            "name": "grerggre"
                        }
                    }
                }
            ]
        },
        "multiType_2": {
            "multiType_2_2": {
                "id": "683308570000",
                "name": {
                    "name2": {
                        "name": "grerggre"
                    }
                }
            }
        }
    }
}


def getids(list_, d):
    if isinstance(d, dict):
        for k, v in d.items():
            if k == 'id':
                list_.append(v)
            elif isinstance(v, list):
                for e in v:
                    getids(list_, e)
            else:
                getids(list_, v)
    return list_


print(getids([], data))

Output:

['683308188000', '683308185000', '24567876543456', '234567654334', '683308570000']

Your JSON object doesn't seem consistent. multiType_1_1 contains a list, that you can iterate over as in the example snippet. multiType_2_2 however is a dictionary, which can not be iterated over in the same way as a list. If you want the singular id under the second result, you can fetch it without the loop with response.root.multiType2.multiType2_2.id. Otherwise, just update your JSON format from source to match the first example field and include the object inside a list.

If you don't have control over the source data and the JSON is changing dynamically, you could do a type check with isinstance(multi_type, list) before trying to iterate over it.

Related