HTML表单数据转递归JSON字典

0 投票
1 回答
1246 浏览
提问于 2025-04-16 01:24

我想把平面的表单数据转换成递归的JSON数据,使用Python或JavaScript。这种JSON数据之后可以被一个模板引擎解析(可以去谷歌搜一下tempest,它的语法跟Django类似)。虽然有很多例子可以把平面数据转换成递归数据,但问题是它不能仅仅是字典或列表。

我尝试了很多方法,但到现在还没成功。所以在思考了至少两周后,我决定在这里问问。

我的表单数据大概是这样的(键名可能会不同):

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'
        },
    ],
}

如你所见,我把字典和列表混合在一起,这让事情变得有点复杂。在我最后一次尝试中,我已经弄明白了在哪里添加列表,在哪里添加字典。这导致了这样的结果:

{'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 个回答

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. “.”这个符号用来分隔树中的节点,并且总是跟在索引数字后面。
  3. 表单数据总是按顺序排列的。(比如:paragraph-0, paragraph-1, paragraph-2),而不是(paragraph-1, paragraph-0, paragraph-3)。

所以,这里是带有注释的代码,解释得更清楚:

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

撰写回答