Reputation: 2689
I have a nested json for a JSON schema like this:
{
"config": {
"x-permission": true
},
"deposit_schema": {
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"control_number": {
"type": "string",
"x-cap-permission": {
"users": [
"[email protected]"
]
}
},
"initial": {
"properties": {
"status": {
"x-permission": {
"users": [
"[email protected]"
]
},
"title": "Status",
"type": "object",
"properties": {
"main_status": {
"type": "string",
"title": "Stage"
}
}
},
"gitlab_repo": {
"description": "Add your repository",
"items": {
"properties": {
"directory": {
"title": "Subdirectory",
"type": "string",
"x-permission": {
"users": [
"[email protected]",
"[email protected]"
]
}
},
"gitlab": {
"title": "Gitlab",
"type": "string"
}
},
"type": "object"
},
"title": "Gitlab Repository",
"type": "array"
},
"title": "Initial Input",
"type": "object"
}
},
"title": "Test Analysis"
}
}
The JSON is nested and I want to have the dict of x-permission
fields with their parent_key like this:
{
"control_number": {"users": ["[email protected]"]},
"initial.properties.status": {"users": ["[email protected]"]},
"initial.properties.gitlab_repo.items.properties.directory": {"users": [
"[email protected]",
"[email protected]"
]}
}
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?
Upvotes: 1
Views: 701
Reputation: 2689
After reading through the comments and the answers. I got this solution working for my use case.
def parse_schema_permission_info(schema):
x_fields = {}
def extract_permission_field(field, parent_field):
for field, value in field.items():
if field == 'x-permission':
x_fields.update({parent_field: value})
if isinstance(value, dict):
key = parent_field + '.' + field
if value.get('x-permission'):
x_fields.update(
{key: value.get('x-permission')}
)
extract_permission_field(value, key)
for field in schema:
extract_permission_field(schema.get(field), field)
return x_fields
Upvotes: 0
Reputation: 196
A few issues I can spot:
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 initial parent_key
valueelif
branch is never executed as the first branch has priority. It is a duplicate.execute(...)
call is ignored. Anything you might find on deeper levels is therefore ignored"initial": {...}
object should return multiple results. You would have to modify the extract(...)
function to allow for multiple results instead of a single onex-permission
or a properties
attribute. This ignores the desired result in the provided "initial"
schema branch which contains x-permission
nested inside a status
and main_status
branch. The easiest solution is to invoke a recursive call every time isinstance(v, dict) == true
Upvotes: 1
Reputation: 350252
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))
Upvotes: 2