Home > Software engineering >  Python convert string holding nested json to dict
Python convert string holding nested json to dict

Time:02-10

I have the following list (notice "keyE" has a dictionary as a string):

[
  {
    "keyA": "Example",
    "keyB": "{\"keyC\":2,\"keyD\":{\"keyE\":\"{\"name\":\"foo\"}\"},\"keyF\":0}"
  },
  {
    "keyA": "Example2",
    "keyB": "{\"keyC\":6,\"keyD\":{\"keyE\":\"{\"name\":\"bar\"}\"},\"keyF\":5}"
  }
]

And I want to convert it to this (it can have any number of nested dictionaries and lists):

[
  {
    "keyA": "Example",
    "keyB": {
      "keyC": 2,
      "keyD": {
        "keyE": {
          "name": "foo"
        }
      },
      "keyF": 0
    }
  },
  {
    "keyA": "Example2",
    "keyB": {
      "keyC": 6,
      "keyD": {
        "keyE": {
          "name": "bar"
        }
      },
      "keyF": 5
    }
  }
]

So far, I have the following but I don't know what to do after the json.loads. I know I have to recursively call the function but not sure how.

import json

def convert(data_list: list) -> list:
  for i in range(len(data_list)):
    obj = data_list[i]

    for key, value in obj.items():
      if isinstance(value, str) and any(char in "{[]}" for char in value):
        try:
          data = json.loads(value)
          # What do I do here?
        except:
          continue

CodePudding user response:

No idea if this'll work for your more complicated cases, but I was able to use ast.literal_eval() and some really janky chained str.replace calls:

import ast


def replace(s):
    return ast.literal_eval(s.replace(r'"{', "{").replace(r'}"', "}"))


x = [{"keyA": "Example",
      "keyB": "{\"keyC\":2,\"keyD\":{\"keyE\":\"{\"name\":\"foo\"}\"},\"keyF\":0}"},
     {"keyA": "Example2",
      "keyB": "{\"keyC\":6,\"keyD\":{\"keyE\":\"{\"name\":\"bar\"}\"},\"keyF\":5}"}]


for d in x:
    for key, value in d.items():
        if "{" in value:
            d[key] = replace(value)

Output:

In [4]: x
Out[4]:
[{'keyA': 'Example',
  'keyB': {'keyC': 2, 'keyD': {'keyE': {'name': 'foo'}}, 'keyF': 0}},
 {'keyA': 'Example2',
  'keyB': {'keyC': 6, 'keyD': {'keyE': {'name': 'bar'}}, 'keyF': 5}}]

In [5]: x[0]["keyB"]["keyD"]["keyE"]["name"]
Out[5]: 'foo'

CodePudding user response:

Your nested key seems like a JSON string that can be loaded into a dictionary using json.loads method.
Though the nested JSON won't get converted to the dictionary that's why I've added the recursive function to address the nested dictionary present in the JSON.

import json
from json import JSONDecodeError


def recurse(d):
    try:
        if isinstance(d, dict):
            loaded_d = d
        else:
            loaded_d = json.loads(d)
        for k, v in loaded_d.items():
            loaded_d[k] = recurse(v)
    except (JSONDecodeError, TypeError):
        return d
    return loaded_d


for d in data_list:
    for key, val in d.items():
        d[key] = recurse(val)

Output:

[
    {
        "keyA": "Example",
        "keyB": {"keyC": 2, "keyD": {"keyE": {"name": "foo"}}, "keyF": 0},
    },
    {
        "keyA": "Example2",
        "keyB": {"keyC": 6, "keyD": {"keyE": {"name": "bar"}}, "keyF": 5},
    },
]
  •  Tags:  
  • Related