递归函数创建层次结构JSON对象?

10

我不是一位足够出色的计算机科学家,无法自己解决这个问题 :(

我有一个API返回JSON响应,看起来像这样:

// call to /api/get/200
{ id : 200, name : 'France', childNode: [ id: 400, id: 500] } 
// call to /api/get/400
{ id : 400, name : 'Paris', childNode: [ id: 882, id: 417] } 
// call to /api/get/500
{ id : 500, name : 'Lyon', childNode: [ id: 998, id: 104] } 
// etc

我想要递归解析它并构建一个分层的JSON对象,看起来像这样:

{ id: 200,
  name: 'France', 
  children: [
     { id: 400,
       name: 'Paris',
       children: [...]
     },
     { id: 500,
       name: 'Lyon', 
       children: [...]
     } 
  ],
} 

目前为止,我已经有了以下代码,它可以解析树的每个节点,但是无法将其保存到JSON对象中。如何修改代码以将其保存到JSON对象中?

hierarchy = {}
def get_child_nodes(node_id):   
    request = urllib2.Request(ROOT_URL + node_id)
    response = json.loads(urllib2.urlopen(request).read())
    for childnode in response['childNode']:
        temp_obj = {}
        temp_obj['id'] = childnode['id']
        temp_obj['name'] = childnode['name']
        children = get_child_nodes(temp_obj['id'])
     // How to save temp_obj into the hierarchy?
get_child_nodes(ROOT_NODE)
这不是作业,但也许我需要做些功课来更好地解决这类问题 :( 感谢任何帮助。

孙子元素包含 ID 还是对象? - wong2
一个对象列表,因此层次结构一直延伸到叶节点。 - flossfan
你的代码里这应该是 response['name'] 而不是 childnode['name'],对吗? - Dr. Jan-Philip Gehrcke
@Jan-PhilipGehrcke - 是的,应该这样。我意识到当前没有存储根节点。 - flossfan
为什么问题和答案中包含urllib2的请求?是因为处理的数据在网站上吗? - HR123r
5个回答

7
def get_node(node_id):   
    request = urllib2.Request(ROOT_URL + node_id)
    response = json.loads(urllib2.urlopen(request).read())
    temp_obj = {}
    temp_obj['id'] = response['id']
    temp_obj['name'] = response['name']
    temp_obj['children'] = [get_node(child['id']) for child in response['childNode']]
    return temp_obj

hierarchy = get_node(ROOT_NODE)

2
您可以使用这个(更紧凑易读的版本)
def get_child_nodes(node_id):   
    request = urllib2.Request(ROOT_URL + node_id)
    response = json.loads(urllib2.urlopen(request).read())
    return {
       "id":response['id'],
       "name":response['name'],
       "children":map(lambda childId: get_child_nodes(childId), response['childNode'])
    }

get_child_nodes(ROOT_NODE)

1

在递归函数的每次调用中,您没有返回任何内容。因此,看起来您只想在循环的每次迭代中将每个temp_obj字典附加到列表中,并在循环结束后返回它。可以尝试以下代码:

def get_child_nodes(node_id):   
    request = urllib2.Request(ROOT_URL + node_id)
    response = json.loads(urllib2.urlopen(request).read())
    nodes = []
    for childnode in response['childNode']:
        temp_obj = {}
        temp_obj['id'] = childnode['id']
        temp_obj['name'] = childnode['name']
        temp_obj['children'] = get_child_nodes(temp_obj['id'])
        nodes.append(temp_obj)
    return nodes

my_json_obj = json.dumps(get_child_nodes(ROOT_ID))

(顺便提一下,请注意不要混用制表符和空格,因为 Python 对此并不太宽容。最好只使用空格。)

你如何从该列表创建所需的层次结构?目标是拥有一组嵌套的字典,然后将其 json.dumps() 化。 - Dr. Jan-Philip Gehrcke
我的代码为什么没有提供这个?每次递归都会形成自己的字典,然后返回给父级。 - Daniel Roseman
对不起,Daniel。我误读了所需的结构和你的代码。 - Dr. Jan-Philip Gehrcke

1
我今天下午遇到了同样的问题,最终修改了一些在网上找到的代码。我已经将代码上传到Github(https://github.com/abmohan/objectjson)以及PyPi(https://pypi.python.org/pypi/objectjson/0.1),包名为'objectjson'。以下是代码:

代码 (objectjson.py)

import json

class ObjectJSON:

  def __init__(self, json_data):

    self.json_data = ""

    if isinstance(json_data, str):
      json_data = json.loads(json_data)
      self.json_data = json_data

    elif isinstance(json_data, dict):
      self.json_data = json_data

  def __getattr__(self, key):
    if key in self.json_data:
      if isinstance(self.json_data[key], (list, dict)):
        return ObjectJSON(self.json_data[key])
      else:
        return self.json_data[key]
    else:
      raise Exception('There is no json_data[\'{key}\'].'.format(key=key))

  def __repr__(self):
    out = self.__dict__
    return '%r' % (out['json_data'])

样例用法

from objectjson import ObjectJSON

json_str = '{ "test": {"a":1,"b": {"c":3} } }'

json_obj = ObjectJSON(json_str)

print(json_obj)           # {'test': {'b': {'c': 3}, 'a': 1}}
print(json_obj.test)      # {'b': {'c': 3}, 'a': 1}
print(json_obj.test.a)    # 1
print(json_obj.test.b.c)  # 3

-1

免责声明:我对 JSON 没有任何了解,所以您可能需要自己整理如何在您的语言中正确编写它 :p。如果我示例中的伪代码太伪了,请随时询问更多细节。

您需要在某个地方返回内容。如果在递归调用中从未返回内容,则无法获取到您新对象的引用,并将其存储在您调用递归的对象中。

def getChildNodes (node) returns [array of childNodes]
    data = getData(fromServer(forThisNode))
    new childNodes array
    for child in data :
        new temp_obj
        temp_obj.stores(child.interestingStuff)
        for grandchild in getChildNodes(child) :
            temp_obj.arrayOfchildren.append(grandchild) 
        array.append(temp_obj)
    return array

如果您的编程语言支持,您可以使用迭代器而不是返回值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接