简体   繁体   English

Python 如何从递归 function 解析嵌套的 json 返回字典?

[英]Python how to return a dictionary from a recursive function parsing a nested json?

I'm trying to parse a nested json file for a specific key value "Date" and return a dictionary that should look like我正在尝试为特定键值“Date”解析嵌套的 json 文件并返回一个看起来应该像这样的字典

{'Date', '2022-05-20T00:00:00Z'}

Here is my code:这是我的代码:

meetingDate_dict = {}
def recursive_json(data,attr,m_dict):
    for k,v in data.items():
        if k == attr:
            for k2,v2 in v.items():
                m_dict = {attr, v2}
                print('IF: ',m_dict)
                return m_dict
        elif isinstance(v,dict):
            print('ELIF: ', k,v)
            return recursive_json(v,attr,m_dict)
        else:
            print('ELSE: ',k,v)

    print('END')

print('RETURN: ',recursive_json(assessment_json, "Date", meetingDate_dict))

Output: Output:

ELSE:  $id 1
ELIF:  DataChangedEntry {'$id': '2', 'PathProperty': '/', 'Metadata': None, 'PreviousValue': None, 'CurrentValue': {'CosewicWsRefId': {'Value': 'QkNlrjq2HL9bhTQqU8-qH'}, 'Date': {'Value': '2022-05-20T00:00:00Z'}, 'YearSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'DateSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'Order': None, 'Type': {'Value': 'REGULAR'}, 'ReportType': {'Value': 'NEW'}, 'Stage': {'Value': 'ASSESSED'}, 'State': {'Value': 'PUBLISHED'}, 'StatusAndCriteria': {'Status': {'Value': 'EXTINCT'}, 'StatusComment': {'EnglishText': None, 'FrenchText': None}, 'StatusChange': {'Value': 'NOT_INITIALIZED'}, 'StatusCriteria': {'EnglishText': None, 'FrenchText': None}, 'ApplicabilityOfCriteria': {'ApplicabilityCriteriaList': []}}, 'Designation': None, 'Note': None, 'DomainEvents': [], 'Version': {'Value': 1651756761385.1248}, 'Id': {'Value': '3z3XlCkaXY9xinAbK5PrU'}, 'CreatedAt': {'Value': 1651756761384}, 'ModifiedAt': {'Value': 1651756785274}, 'CreatedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}, 'ModifiedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}}}
ELSE:  $id 2
ELSE:  PathProperty /
ELSE:  Metadata None
ELSE:  PreviousValue None
ELIF:  CurrentValue {'CosewicWsRefId': {'Value': 'QkNlrjq2HL9bhTQqU8-qH'}, 'Date': {'Value': '2022-05-20T00:00:00Z'}, 'YearSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'DateSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'Order': None, 'Type': {'Value': 'REGULAR'}, 'ReportType': {'Value': 'NEW'}, 'Stage': {'Value': 'ASSESSED'}, 'State': {'Value': 'PUBLISHED'}, 'StatusAndCriteria': {'Status': {'Value': 'EXTINCT'}, 'StatusComment': {'EnglishText': None, 'FrenchText': None}, 'StatusChange': {'Value': 'NOT_INITIALIZED'}, 'StatusCriteria': {'EnglishText': None, 'FrenchText': None}, 'ApplicabilityOfCriteria': {'ApplicabilityCriteriaList': []}}, 'Designation': None, 'Note': None, 'DomainEvents': [], 'Version': {'Value': 1651756761385.1248}, 'Id': {'Value': '3z3XlCkaXY9xinAbK5PrU'}, 'CreatedAt': {'Value': 1651756761384}, 'ModifiedAt': {'Value': 1651756785274}, 'CreatedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}, 'ModifiedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}}
ELIF:  CosewicWsRefId {'Value': 'QkNlrjq2HL9bhTQqU8-qH'}
ELSE:  Value QkNlrjq2HL9bhTQqU8-qH
END
RETURN:  None

So this way doesn't ever print the correct key:value pair, and returns None.所以这种方式永远不会打印出正确的键值对,并返回 None。 If I remove the return statement in the elif I at least get the correct print out from the if statement, but I still get None returned:如果我删除了elif中的return语句,我至少从if语句中得到了正确的打印,但我仍然没有返回None

meetingDate_dict = {}
def recursive_json(data,attr,m_dict):
    for k,v in data.items():
        if k == attr:
            for k2,v2 in v.items():
                m_dict = {attr, v2}
                print('IF: ',m_dict)
                return m_dict
        elif isinstance(v,dict):
            print('ELIF: ', k,v)
            recursive_json(v,attr,m_dict)
        else:
            print('ELSE: ',k,v)

    print('END')

print('RETURN: ',recursive_json(assessment_json, "Date", meetingDate_dict))

Output: Output:

ELSE:  $id 1
ELIF:  DataChangedEntry {'$id': '2', 'PathProperty': '/', 'Metadata': None, 'PreviousValue': None, 'CurrentValue': {'CosewicWsRefId': {'Value': 'QkNlrjq2HL9bhTQqU8-qH'}, 'Date': {'Value': '2022-05-20T00:00:00Z'}, 'YearSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'DateSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'Order': None, 'Type': {'Value': 'REGULAR'}, 'ReportType': {'Value': 'NEW'}, 'Stage': {'Value': 'ASSESSED'}, 'State': {'Value': 'PUBLISHED'}, 'StatusAndCriteria': {'Status': {'Value': 'EXTINCT'}, 'StatusComment': {'EnglishText': None, 'FrenchText': None}, 'StatusChange': {'Value': 'NOT_INITIALIZED'}, 'StatusCriteria': {'EnglishText': None, 'FrenchText': None}, 'ApplicabilityOfCriteria': {'ApplicabilityCriteriaList': []}}, 'Designation': None, 'Note': None, 'DomainEvents': [], 'Version': {'Value': 1651756761385.1248}, 'Id': {'Value': '3z3XlCkaXY9xinAbK5PrU'}, 'CreatedAt': {'Value': 1651756761384}, 'ModifiedAt': {'Value': 1651756785274}, 'CreatedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}, 'ModifiedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}}}
ELSE:  $id 2
ELSE:  PathProperty /
ELSE:  Metadata None
ELSE:  PreviousValue None
ELIF:  CurrentValue {'CosewicWsRefId': {'Value': 'QkNlrjq2HL9bhTQqU8-qH'}, 'Date': {'Value': '2022-05-20T00:00:00Z'}, 'YearSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'DateSentToMinister': {'Value': '0001-01-01T00:00:00'}, 'Order': None, 'Type': {'Value': 'REGULAR'}, 'ReportType': {'Value': 'NEW'}, 'Stage': {'Value': 'ASSESSED'}, 'State': {'Value': 'PUBLISHED'}, 'StatusAndCriteria': {'Status': {'Value': 'EXTINCT'}, 'StatusComment': {'EnglishText': None, 'FrenchText': None}, 'StatusChange': {'Value': 'NOT_INITIALIZED'}, 'StatusCriteria': {'EnglishText': None, 'FrenchText': None}, 'ApplicabilityOfCriteria': {'ApplicabilityCriteriaList': []}}, 'Designation': None, 'Note': None, 'DomainEvents': [], 'Version': {'Value': 1651756761385.1248}, 'Id': {'Value': '3z3XlCkaXY9xinAbK5PrU'}, 'CreatedAt': {'Value': 1651756761384}, 'ModifiedAt': {'Value': 1651756785274}, 'CreatedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}, 'ModifiedBy': {'Value': 'Geordie.Powers@ec.gc.ca'}}
ELIF:  CosewicWsRefId {'Value': 'QkNlrjq2HL9bhTQqU8-qH'}
ELSE:  Value QkNlrjq2HL9bhTQqU8-qH
END
IF:  {'Date', '2022-05-20T00:00:00Z'}
END
ELSE:  EventAction Create
ELIF:  EventDataChange {'$ref': '2'}
ELSE:  $ref 2
END
ELSE:  CorrelationId 3z3XlCkaXY9xinAbK5PrU
ELSE:  EventId WGxlewsUAHayLHZ2LHvFk
ELSE:  EventTimeUtc 2022-05-06T13:15:31.7463355Z
ELSE:  EventDataVersion 1.0.0
ELSE:  EventType AssessmentCreatedInfrastructure
END
RETURN:  None

The json file: json 文件:

{
  "$id": "1",
  "DataChangedEntry": {
    "$id": "2",
    "PathProperty": "/",
    "Metadata": null,
    "PreviousValue": null,
    "CurrentValue": {
      "CosewicWsRefId": {
        "Value": "QkNlrjq2HL9bhTQqU8-qH"
      },
      "Date": {
        "Value": "2022-05-20T00:00:00Z"
      },
      "YearSentToMinister": {
        "Value": "0001-01-01T00:00:00"
      },
      "DateSentToMinister": {
        "Value": "0001-01-01T00:00:00"
      },
      "Order": null,
      "Type": {
        "Value": "REGULAR"
      },
      "ReportType": {
        "Value": "NEW"
      },
      "Stage": {
        "Value": "ASSESSED"
      },
      "State": {
        "Value": "PUBLISHED"
      },
      "StatusAndCriteria": {
        "Status": {
          "Value": "EXTINCT"
        },
        "StatusComment": {
          "EnglishText": null,
          "FrenchText": null
        },
        "StatusChange": {
          "Value": "NOT_INITIALIZED"
        },
        "StatusCriteria": {
          "EnglishText": null,
          "FrenchText": null
        },
        "ApplicabilityOfCriteria": {
          "ApplicabilityCriteriaList": []
        }
      },
      "Designation": null,
      "Note": null,
      "DomainEvents": [],
      "Version": {
        "Value": 1651756761385.1248
      },
      "Id": {
        "Value": "3z3XlCkaXY9xinAbK5PrU"
      },
      "CreatedAt": {
        "Value": 1651756761384
      },
      "ModifiedAt": {
        "Value": 1651756785274
      },
      "CreatedBy": {
        "Value": "a@a"
      },
      "ModifiedBy": {
        "Value": "a@a"
      }
    }
  },
  "EventAction": "Create",
  "EventDataChange": {
    "$ref": "2"
  },
  "CorrelationId": "3z3XlCkaXY9xinAbK5PrU",
  "EventId": "WGxlewsUAHayLHZ2LHvFk",
  "EventTimeUtc": "2022-05-06T13:15:31.7463355Z",
  "EventDataVersion": "1.0.0",
  "EventType": "AssessmentCreatedInfrastructure"
}

I think the problem here is because when looking for attr in deeper levels, you didn't check whether recursive_json(v,attr,m_dict) is returning the actual desired value or None and just return it anyway.我认为这里的问题是因为在更深层次上寻找attr时,您没有检查recursive_json(v,attr,m_dict)是否返回实际所需的值或None并且无论如何都返回它。 Changing the code to:将代码更改为:

def recursive_json(data,attr,m_dict):
    ...
       # find attr value in deeper levels
       elif isinstance(v,dict):
           result = recursive_json(v,attr,m_dict)
           # if result is not None, return it
           if result:
               return result
    ...

I would refactor your recursive_json function as follows, removing m_dict as it seems unnecessary:我会重构你的recursive_json function 如下,删除m_dict似乎没有必要:

def recursive_json(data: dict, lookup_key: str, value_key: str = "Value"):
    # look for all key-value pairs at current levels
    for k, v in data.items():
        # Check if current pair satisfies the following conditions:
        # - key equal to lookup key
        # - value is a dictionary
        # - value dictionary has subkey named `Value`
        if k == lookup_key and isinstance(v, dict) and value_key in v:
            return {lookup_key: v.get(value_key)}
        
        # else if value is a dictionary, search `lookup_key` in deeper levels
        elif isinstance(v, dict):
            lookup_result = recursive_json(v, lookup_key, value_key)
            
            # if value for `lookup_key` is found in deeper levels, return the value
            if lookup_result:
                return lookup_result
    
    # return None as no satisfied value found
    return None

Edit: For multiple instances of lookup_key , try the following method:编辑:对于lookup_key的多个实例,请尝试以下方法:

def recursive_json(data: dict, lookup_keys: list, value_key: str = "Value"):
    if isinstance(lookup_keys, str):
        lookup_keys = [lookup_keys]

    # BFS
    search_q = [data]
    # look for all key-value pairs at current levels
    lookup_result = {}
    while search_q and lookup_keys:
        in_search_dict = search_q.pop(0)
        for k, v in in_search_dict.items():
            # Check if current pair satisfies the following conditions:
            # - key equal to lookup key
            # - value is a dictionary
            # - value dictionary has subkey named `Value`
            if isinstance(v, dict):
                if value_key in v and k in lookup_keys:
                    # remove `value_key` from current dict
                    value = v.pop(value_key)
                    # update lookup result
                    lookup_result.update({k: value})
                    # remove found key from lookup keys
                    lookup_keys.remove(k)

                    # if all lookup keys are found, break the while loop
                    if not lookup_keys:
                        break
                if v:
                    search_q.append(v)

    # return lookup result
    return lookup_result

print(recursive_json(assessment_json, ["Date", "ModifiedBy", "CreatedBy"]))
# {'Date': '2022-05-20T00:00:00Z', 'CreatedBy': 'a@a', 'ModifiedBy': 'a@a'}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM