简体   繁体   English

Python将包含嵌套json的字符串转换为dict

[英]Python convert string holding nested json to dict

I have the following list (notice "keyE" has a dictionary as a string):我有以下列表(注意“keyE”有一个字典作为字符串):

[
  {
    "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 .到目前为止,我有以下内容,但我不知道在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

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:不知道这是否适用于您更复杂的情况,但我能够使用ast.literal_eval()和一些非常笨拙的链式str.replace调用:

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'

Your nested key seems like a JSON string that can be loaded into a dictionary using json.loads method.您的嵌套键看起来像一个 JSON 字符串,可以使用json.loads方法加载到字典中。
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.尽管嵌套的 JSON 不会转换为字典,这就是为什么我添加了递归函数来解决 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},
    },
]

Okay, here is recursive solution:好的,这是递归解决方案:

import json
from json import JSONDecodeError

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

def rec_convert(data):

  for k, v in data.items():
    try:
      if type(v) == dict:
        rec_convert(v)
        continue
      data[k] = json.loads(v)
      rec_convert(data[k])
    except (JSONDecodeError, TypeError):
      continue

for el in data:
  rec_convert(el)

print("raw print:")

print(data)

print("pretty print")

print(json.dumps(data, indent=2))

and output:和输出:

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

I've updated Vishal Singh's answer to accommodate for lists inside a dictionary.我已经更新了 Vishal Singh 的答案以适应字典中的列表。

def decode_json_recursively(obj):
    try:
        if isinstance(obj, list):
            data = [decode_json_recursively(el) for el in obj]
        elif isinstance(obj, dict):
            data = obj
        else:
            data = json.loads(obj)

        if isinstance(data, dict):
            for k, v in data.items():
                data[k] = decode_json_recursively(v)
    except (JSONDecodeError, TypeError, AttributeError):
        return obj
    return data

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

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