I'm trying to find a way to add/remove one or more elements in a JSON object given the parent object keys of these elements regardless of the schema definition of the object.
Let's make an example. Suppose we have the following JSON object:
{
"field1": "",
"field2": "",
"list1": [
{
"list1_field1": "",
"list1_obj1": {
"list1_obj1_field1": "",
},
"list1_field2": "",
},
{
"list1_field1": "",
"list1_obj1": {
"list1_obj1_field1": "",
},
"list1_field2": "",
"list1_field3": "",
"list1_sublist1": [
{
"list1_sublist1_field1": ""
}
]
}
]
}
Now, let's assume that I'd like to add a new field in the "list1_obj1" object in all of the elements of "list1". Then, the keys would be "list1" and "list1_obj1" and the new field would be, for example,"list1_obj1_field2".
To sum up, given in input the keys "list1" and "list1_obj1" I'd like to add or remove a new field at this nested level, but not considering the schema of the JSON object.
Of course, the assumption is that "list1" and "list1_obj1" exist in the JSON file, and in case of removal, "list1_obj1_field2" exists as well.
Now, the most problematic thing on which I'm struggling is to take into account nested object lists. If I don't consider that constraint, I could implement a solution like the ones in the following threads 1 2.
Then, trying to achieve that, I imagined a solution like the following:
# Remove item from the json object
# Suppose the json object is stored in a variable called "json_object"
keys = "list1.list1_obj1.list1_obj1_field2".split(".")
item = json_object
for i,key in enumerate(keys):
if isinstance(item,dict):
print("it's a dict")
if key in item.keys():
print(item)
if i == len(keys)-1:
# last item, so we can remove it
else:
item = item[key]
else:
print("it's a list")
# loop on the list and for each element remove the item
in case the nested item is a list I think I should iterate on that and for each element find the correct item to remove. However, I find this solution inefficient. Also, I tried unsuccessfully to figure out a way to make the function recursive.
Any hint would be really appreciated.
Many thanks
EDIT 1:
I managed to implement a first recursive version.
def remove_element(obj, keys, current_key=0):
"""
obj: the item passed in the function. At the beginning it is the entire json object
keys: list that represents the complete key path from the root to the interested field
current_key: index which points to keys list elements
"""
if isinstance(obj, dict):
for k in obj.keys():
if k == keys[current_key]:
if isinstance(obj[k], dict):
obj[k] = remove_element(obj[k], keys, current_key+1)
elif isinstance(obj[k], list):
for i in range(len(obj[k])):
obj[k][i] = remove_element(obj[k][i],keys, current_key+1)
else:
obj[k] = ""
return obj
Currently, the function doesn't delete the desired field, but it only set it to "", since I would get a RuntimeError: dictionary changed size during iteration if I try to delete it (del obj[k]).
The improvement is that now it's possible to reach a field without consider the schema. However, it's still not possible to delete it and it's possible to access only to the fields which don't have children (everything that is not a list or dict).