I have a nested json for a JSON schema like this:
{
"_user_edited":
{"type": "boolean"},
"_experiment":
{"type": "string",
"x-permission": {"users": [1, 2]}},
"initial": {
"properties": {
"status": {
"x-permission": {"users": [1, 2, 3, 4, 5]},
"title": "Status",
"type": "object",
"properties": {
"main_status": {
"type": "string",
"title": "Stage",
"x-permission": {"users": [2, 3, 5]},
"enum": ["Analysis"],
}
},
}
}
},
}
The JSON is nested and I want to have the dict of x-permission
fields with their parent_key like this:
{
"_experiment": {"users": [1, 2]},
"initial.status": {"users": [1, 2, 3, 4, 5]},
"initial.status.main_status": {"users": [2, 3, 5]}
}
I am trying to do implement recursive logic for every key in JSON like this:
def extract(obj, parent_key):
"""Recursively search for values of key in JSON tree."""
for k, v in obj.items():
key = parent_key '.' k
if isinstance(v, dict):
if v.get('x-permission'):
return key, v.get('x-permission')
elif v.get('properties'):
return extract(v.get('properties'), key)
return None, None
def collect_permission_info(object_):
# _schema = _schema.deposit_schema.get('properties')
_schema = object_ # above json
x_cap_fields = {}
for k in _schema:
parent_key, permission_info = extract(_schema.get(k), k)
if parent_key and permission_info:
x_cap_fields.update({parent_key: permission_info})
return x_cap_fields
I am getting empty dict now, what I am missing here?
CodePudding user response:
You could use this generator of key/value tuples:
def collect_permission_info(schema):
for key, child in schema.items():
if isinstance(child, dict):
if "x-permission" in child:
yield key, child["x-permission"]
if "properties" in child:
for rest, value in collect_permission_info(child["properties"]):
yield key "." rest, value
Then call it like this:
result = dict(collect_permission_info(schema))
CodePudding user response:
A few issues I can spot:
- You use the
parent_key
directly in the recursive function. In a case when multiple properties exist in an object ("_experiment"
has 2 properties), the path will be incorrect (e.g._experiment.type.x-permission
is constructed in second loop call). Use a new variable so that each subsequent for loop call uses the initialparent_key
value - The
elif
branch is never executed as the first branch has priority. It is a duplicate. - The return value from the recursive
execute(...)
call is ignored. Anything you might find on deeper levels is therefore ignored - Judging by your example json schema and the desired result, a recursive call on the
"initial": {...}
object should return multiple results. You would have to modify theextract(...)
function to allow for multiple results instead of a single one - You only check if an object contains a
x-permission
or aproperties
attribute. This ignores the desired result in the provided"initial"
schema branch which containsx-permission
nested inside astatus
andmain_status
branch. The easiest solution is to invoke a recursive call every timeisinstance(v, dict) == true