获取父键和嵌套json中的嵌套值



我有一个嵌套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))

我可以发现一些问题:

  1. 在递归函数中直接使用parent_key。在一个对象中存在多个属性的情况下("_experiment"有2个属性),路径将是不正确的(例如_experiment.type.x-permission在第二个循环调用中构造)。使用一个新变量,以便每个后续for循环调用都使用初始parent_key
  2. elif分支永远不会执行,因为第一个分支具有优先级。这是一个副本。
  3. 忽略递归execute(...)调用的返回值。因此,您可能在更深层次上发现的任何内容都将被忽略
  4. 根据示例json模式和期望的结果判断,对"initial": {...}对象的递归调用应该返回多个结果。您必须修改extract(...)函数以允许多个结果而不是单个结果
  5. 您只检查对象是否包含x-permissionproperties属性。这将忽略所提供的"initial"模式分支中的期望结果,该分支包含嵌套在statusmain_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