Search code examples
pythonjsonnestedattributesparent

Find parent name of a json attribute - unknown structure - Python


There is a JSON file with unknown structure.

I need to find an attribute of a known name in this file and, if it exists, return the name of its parent node, or nodes (if there are multiple instances of the attribute).

Example #1:

Input file:

{
    "attr1": {
        "attr2": {
            "attr3": "somevalue"
            "attr7": "someothervalue"
        }
    }
}

Attribute name: "attr7"

Expected return value: "attr2"

Example #2:

Input file:

{
    "some": {
        "deeply": {
            "nested": {
                "stuff": {
                    "array1": [
                        {"this":"value1"},
                        {"this":"value2"},
                        {"this":"value3"}
                     ]
                }
            }
        }
    }
}

Attribute name: "this"

Expected return value: "array1"

Example #3: (similar to #2 but with a duplicate)

Input file:

{
    "some": {
        "deeply": {
            "nested": {
                "this": {
                    "array1": [
                        {"this":"value1"},
                        {"this":"value2"},
                        {"this":"value3"}
                     ]
                }
            }
        }
    }
}

Attribute name: "this"

Expected return value: "array1", "nested"

My starting point is:

import json

if __name__ == "__main__":
    jsonFileName = "file.json"
    attributeName = "this"
    jsonFile = open(jsonFileName, "r")
    jsonData = json.load(jsonFile)
    # ???

I found this one: Access JSON element with parent name unknown but it is not really applicable in my case because they know the structure of their data and I don't.

Any hints?


Solution

  • So, with a bit of a back and forth with a more experienced colleague I came up with the following solution:

    def findKey(jsonData: json, keyName: str, accessPath: str):
        if isinstance(jsonData, str):
            return None
        for key in jsonData.keys():
            if key == keyName:
                return accessPath + f"/{keyName};"
            if isinstance(jsonData[key], list):
                for jd in jsonData[key]:
                    fk = findKey(jd, keyName, accessPath + "/[]" + key)
                    if(fk):
                        return fk
            elif isinstance(jsonData[key], dict):
                fk = findKey(jsonData[key], keyName, accessPath + "/{}" + key)
                if(fk):
                    return fk
        return None