将HTML表单数据转换为递归JSON字典

您想要将平面表单数据转换为递归JSON数据,该JSON数据可以稍后由模板引擎(google for 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'
        },
    ],
}

如您所见,您将 dict 与 list 混合在一起,这使其有点困难。在您最后一次尝试中,您达到了脚本可以弄清楚在何处添加列表和在何处添加字典的程度。这产生以下结果:

{'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"
}

您还能看到完整的脚本。您知道它可以更简洁,但您将在它工作后重构它。

您做错了什么?您是否完全遗漏了什么?

2、解决方案

一种解决方法是使用以下函数:

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'])

该函数做出以下假设:

    • 字符用于指定特定节点类型的哪个节点,后面跟着一个数字。
  • . 字符分隔树中的节点,并且总是在索引号后面。
  • 表单数据将始终按顺序进行。(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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值