HTML表单数据递归json dict

时间:2010-07-16 13:21:05

标签: javascript python html json recursion

我想将平面表单数据转换为python或javascript中的递归JSON数据。此JSON数据稍后可以由模板引擎解释(google for tempest,它具有类似django的语法)。有很多例子可以将平面数据转换为递归数据,但问题是它不能只是一个字典或列表。

我试图以多种方式做到这一点,但还没有成功。所以在我挠了头至少两个星期之后,我决定在这里问一个问题。

formdata是这样的(键名可能不同):

formdata = [
    {"formname": "name", "formvalue": "Roel Kramer"},
    {"formname": "email", "formvalue": "blaat@blaat.nl"},
    {"formname": "paragraph-0.title", "formvalue": "test titel 1"},
    {"formname": "paragraph-0.body", "formvalue": "bla bla body 1"},
    {"formname": "paragraph-0.image-0.src", "formvalue": "src 1"},
    {"formname": "paragraph-0.image-1.src", "formvalue": "src 2"},
    {"formname": "paragraph-1.title", "formvalue": "test titel 2"},
    {"formname": "paragraph-1.body", "formvalue": "bla bla body 2"},
    {"formname": "paragraph-1.image-0.src", "formvalue": "src 3"},
    {"formname": "paragraph-1.image-1.src", "formvalue": "src 4"},
    {"formname": "paragraph-1.image-2.src", "formvalue": "src 5"},
    {"formname": "paragraph-2.title", "formvalue": "test titel 3"},
    {"formname": "paragraph-2.body", "formvalue": "bla bla body 3"},
    {"formname": "paragraph-2.image-0.src", "formvalue": "src 6"},
    {"formname": "paragraph-2.image-1.src", "formvalue": "src 7"},
]

我想将其转换为以下格式:

{'paragraph':
    [
        {
        'image': [{'src': 'src 1'}, {'src': 'src 2'}],
        'body': 'body 2',
        'title': 'titel 2'
        },
        {
        'image': [{'src': 'src 3'}, {'src': 'src 4'}, {'src': 'src 5'}],
        'body': 'body 2',
        'title': 'titel 2'
        },
        {
        'image': [{'src': 'src 6'}, {'src': 'src 7'},
        'body': 'body 3',
        'title': 'titel 3'
        },
    ],
}

正如您所看到的,我将dicts与列表混合在一起,这使得它更难一些。在我的最后一次尝试中,我得到了脚本确定添加列表的位置以及添加dicts的位置。结果如下:

{'paragraph': [{'image': []}, {'image': []}, {'image': []}]}

但是当我添加数据时,结果不符合我的预期。

{"paragraph": [{"body": "bla bla body 1", "image": {"src": "src 7"}, "title": "test titel 1"}, {"body": "bla bla body 2", "image": {"src": "src 5"}, "title": "test titel 2"}, {"body": "bla bla body 3", "image": {"src": "src 3"}, "title": "test titel 3"}, {"image": {"src": "src 6"}}], "name": "Roel Kramer", "email": "contact@roelkramer.nl"}

可在github gist查看总脚本。我知道它可以更清洁,但是当它工作时我会重构它。

我做错了什么?我完全错过了什么吗? 非常感谢!

1 个答案:

答案 0 :(得分:1)

好吧,如果你知道格式是一致的,那么这样的东西就可以了:

def add_data(node, name, value):
    if '-' not in name:
        node[name] = value
    else:
        key = name[:name.index('-')]
        node_index = int(name[len(key) + 1:name.index('.')])
        node.setdefault(key, [])
        if node_index >= len(node[key]):
            node[key].append({})
        add_data(node[key][node_index],
                 name[name.index('.') + 1:],
                 value)

然后使用它,只需执行以下操作:

root_node = {}
for data in formdata:
    add_data(root_node, data['formname'], data['formvalue'])

该函数做出以下假设:

  1. - 字符用于指定特定节点类型的哪个节点,并遵循该节点 用数字。
  2. 。 character分隔树中的节点,并始终遵循索引号。
  3. 表单数据将始终按顺序排列。 (第0段,第1段,第2段)而不是(第1段第0段第3段)。
  4. 所以,这里的代码带有解释它的注释:

    def add_data(node, name, value):
        # We're at a parent node (ex: paragraph-0), so we need to drill down until
        # we find a leaf node
        if '-' in name:
            key = name[:name.index('-')]
            node_index = int(name[len(key) + 1:name.index('.')])
    
            # Initialize the parent node if needed by giving it a dict to store it's
            # information nodes
            node.setdefault(key, [])
            if node_index >= len(node[key]):
                node[key].append({})
    
            # Drill down the tree by calling this function again, making this
            # parent node the root
            add_data(node[key][node_index],
                     name[name.index('.') + 1:],
                     value)
    
        # We're at a leaf node, so just add it to the parent node's information
        # ex:  The first formdata item would make the root_node dict look like
        # { 'name': 'Roel Kramer' }
        else:
            node[name] = value
    

    以下是一个有效的例子:http://pastebin.com/wpMPXs1r