我有一个嵌套json json模式像这样:
{
"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": [
"test@test.com"
]
}
},
"initial": {
"properties": {
"status": {
"x-permission": {
"users": [
"test3@test.com"
]
},
"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": [
"test1@test.com",
"test2@test.com"
]
}
},
"gitlab": {
"title": "Gitlab",
"type": "string"
}
},
"type": "object"
},
"title": "Gitlab Repository",
"type": "array"
},
"title": "Initial Input",
"type": "object"
}
},
"title": "Test Analysis"
}
}
JSON是嵌套的,我想有x-permission
字段的字典,它们的parent_key像这样:
{
"control_number": {"users": ["test@test.com"]},
"initial.properties.status": {"users": ["test3@test.com"]},
"initial.properties.gitlab_repo.items.properties.directory": {"users": [
"test1@test.com",
"test2@test.com"
]}
}
我正试图为JSON中的每个键实现递归逻辑,如下所示:
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
我现在得到空字典,我在这里错过了什么?
可以使用以下键/值元组生成器:
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
然后像这样调用它:
result = dict(collect_permission_info(schema))
我可以发现一些问题:
- 在递归函数中直接使用
parent_key
。在一个对象中存在多个属性的情况下("_experiment"
有2个属性),路径将是不正确的(例如_experiment.type.x-permission
在第二个循环调用中构造)。使用一个新变量,以便每个后续for循环调用都使用初始parent_key
值 elif
分支永远不会执行,因为第一个分支具有优先级。这是一个副本。- 忽略递归
execute(...)
调用的返回值。因此,您可能在更深层次上发现的任何内容都将被忽略 - 根据示例json模式和期望的结果判断,对
"initial": {...}
对象的递归调用应该返回多个结果。您必须修改extract(...)
函数以允许多个结果而不是单个结果 - 您只检查对象是否包含
x-permission
或properties
属性。这将忽略所提供的"initial"
模式分支中的期望结果,该分支包含嵌套在status
和main_status
分支中的x-permission
。最简单的解决方案是每次调用一个递归调用isinstance(v, dict) == true
看完评论和答案后。我让这个解决方案为我的用例工作。
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