简体   繁体   中英

Edit dict recursively in Python

I have a dict like this

{
  "library": [
    {
      "_type": "Host",
      "parameters": "JSON STRING",
      "superclassOf": [
        {
          "_type": "LinuxHost",
          "superclassOf": [
            {
              "_type": "Ubuntu",
              "superclassOf": [
                {
                  "_type": "Ubuntu1604",
                  "parameters": "JSON STRING"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Where JSON STRING is a dict in a string form (eg '{"property1":"value1","property2":"value2"}' ). What I am looking for is a way to navigate recoursively the supeclassOf property and convert these Json strings to real parts of json, and return the full dict once edited.

EDIT : note that supeclassOf 's values are lists. So everywhere there's a superclassOf there can be multiple elements, each having (or not) properties parameters and superclassOf

EDIT2 using Prem Anand's answer I get this error:

Traceback (most recent call last):
  File "C:/Users/ceccolig/PycharmProjects/api/api.py", line 61, in <module>
    main()
  File "C:/Users/ceccolig/PycharmProjects/api/api.py", line 52, in main
    process_list_or_dict(library)
  File "C:/Users/ceccolig/PycharmProjects/api/api.py", line 45, in process_list_or_dict
    process_list_or_dict(v)
  File "C:/Users/ceccolig/PycharmProjects/api/api.py", line 45, in process_list_or_dict
    process_list_or_dict(v)
  File "C:/Users/ceccolig/PycharmProjects/api/api.py", line 45, in process_list_or_dict
    process_list_or_dict(v)
  [Previous line repeated 5 more times]
  File "C:/Users/ceccolig/PycharmProjects/api/api.py", line 43, in process_list_or_dict
    ld[k] = process_str(v)
  File "C:/Users/ceccolig/PycharmProjects/api/api.py", line 37, in process_str
    return json.loads(s)
  File "C:\Users\ceccolig\AppData\Local\Programs\Python\Python38-32\lib\json\__init__.py", line 357, in loads
    return _default_decoder.decode(s)
  File "C:\Users\ceccolig\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Users\ceccolig\AppData\Local\Programs\Python\Python38-32\lib\json\decoder.py", line 353, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

You can use json.loads to convert the json string to dict. Navigate through each element of your dict, check if it is of type dict or list or string and process each type accordingly

import json

def process_str(s):
    if s and s[0]=='{' and s[-1]=='}':
        return json.loads(s)
    return s

def process_list_or_dict(ld):
    for k,v in enumerate(ld) if isinstance(ld, list) else ld.items():
        if isinstance(v, str):
            ld[k] = process_str(v)
        elif isinstance(v, (list, dict)):
            process_list_or_dict(v)

Example

dct = {'library': [{'_type': 'Host', 'parameters': '{"property1":"value1","property2":"value2"}', 'superclassOf': [{'_type': 'LinuxHost', 'superclassOf': [{'_type': 'Ubuntu', 'superclassOf': [{'_type': 'Ubuntu1604', 'parameters': '{"property3":"value3","property4":"value4"}'}]}]}]}]}

process_list_or_dict(dct)

print(json.dumps(dct, indent=4))

Output

{
    "library": [
        {
            "_type": "Host",
            "parameters": {
                "property1": "value1",
                "property2": "value2"
            },
            "superclassOf": [
                {
                    "_type": "LinuxHost",
                    "superclassOf": [
                        {
                            "_type": "Ubuntu",
                            "superclassOf": [
                                {
                                    "_type": "Ubuntu1604",
                                    "parameters": {
                                        "property3": "value3",
                                        "property4": "value4"
                                    }
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

Okay now I got you I hope. With reference to this question , I modified the answer so that it should work for you. Hope this is what you are looking for:

import json

data = {
  "library": [
    {
      "_type": "Host",
      "parameters": '{"property1":"value1","property2":"value2"}',
      "superclassOf": [
        {
          "_type": "LinuxHost",
          "superclassOf": [
            {
              "_type": "Ubuntu",
              "superclassOf": [
                {
                  "_type": "Ubuntu1604",
                  "parameters": '{"property1":"value1","property2":"value2"}'
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}


# if you want to modify a specific key's value where you only know the key
def replace(data, key_match, repl):
    if isinstance(data, dict):
        return {k: replace((v if k != key_match else repl), key_match, repl) for k, v in data.items()}
    elif isinstance(data, list):
        return [replace(i, key_match, repl) for i in data]
    elif isinstance(data, str):
        try:
            data = json.loads(data)
            return replace(data, key_match, repl)
        except ValueError:
            return data
    else:
        return data

print(replace(data, "property1", "Modified"))
# {'library': [{'_type': 'Host', 'parameters': {'property1': 'Modified', 'property2': 'value2'}, 'superclassOf': [{'_type': 'LinuxHost', 'superclassOf': [{'_type': 'Ubuntu', 'superclassOf': [{'_type': 'Ubuntu1604', 'parameters': {'property1': 'Modified', 'property2': 'value2'}}]}]}]}]}

EDIT

If you only want to convert the json.

def convertJSON(data):
    if isinstance(data, dict):
        return {k: convertJSON(v) for k, v in data.items()}
    elif isinstance(data, list):
        return [convertJSON(i) for i in data]
    elif isinstance(data, str):
        try:
            data = json.loads(data)
            return convertJSON(data)
        except ValueError:
            return data
    else:
        return data

print(convertJSON(data))
# {'library': [{'_type': 'Host', 'parameters': {'property1': 'value1', 'property2': 'value2'}, 'superclassOf': [{'_type': 'LinuxHost', 'superclassOf': [{'_type': 'Ubuntu', 'superclassOf': [{'_type': 'Ubuntu1604', 'parameters': {'property1': 'value1', 'property2': 'value2'}}]}]}]}]}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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