【发布时间】:2018-03-28 20:58:46
【问题描述】:
我正在尝试反序列化通过jQuery.param() 函数序列化的复杂数据。
我找到了 python 库 jquery-unparam,但不幸的是它不能很好地管理可能发生的复杂结构。
我做了一个涵盖所有可能性的例子,这里是数据:
sample = {
'some': 'value',
'with': True,
'but[]': ['contains', 'also', 'some', 'array'],
'or[0]': 'even',
'or[1]': 'numbered',
'or[2]': 'arrays',
'also[0][some]': 'with',
'also[0][sub]': 'complex',
'also[0][values]': 'structure',
'and[finally]': 'some',
'and[easier]': 'ones'
}
此数据是 Flask 中 request.form.to_dict() 的结果。如果需要,这里是jQuery.param()处理后的原始值:
"some=value&with=true&but%5B%5D=contains&but%5B%5D=also&but%5B%5D=some&but%5B%5D=array&or%5B0%5D=even&or%5B1%5D=numbered&or%5B2%5D=arrays&also%5B0%5D%5Bsome%5D=with&also%5B0%5D%5Bsub%5D=complex&also%5B0%5D%5Bvalues%5D=structure&and%5Bfinally%5D=some&and%5Beasier%5D=ones"
现在,如果您直接运行 Python 库中的代码,您会得到以下结果:
{"and": {"finally": "some", "easier": "ones"}, "some": "value", "but": ["contains", "also", "some", "array"], "also": {"0": {"values": "structure", "some": "with", "sub": "complex"}}, "with": "true", "or": {"1": "numbered", "0": "even", "2": "arrays"}}
问题是,also 的键应该是一个列表,而不是一个字典,应该是这样的:
{"and": {"finally": "some", "easier": "ones"}, "some": "value", "but": ["contains", "also", "some", "array"], "also": [{"values": "structure", "some": "with", "sub": "complex"}], "with": "true", "or": {"1": "numbered", "0": "even", "2": "arrays"}}
但我坚持让这个工作。
到目前为止,这是我的代码(从库更改为直接从 Flask 的 to_dict 代码工作):
#!/usr/bin/python
# -*- coding: utf-8 -*-
import re, json
def parse_key_pair(key, val):
groups = re.findall(r"\[.*?\]", key)
groups_joined = ''.join(groups)
if key[-len(groups_joined):] == groups_joined:
key = key[:-len(groups_joined)]
for group in reversed(groups):
if group == '[]':
val = val
else:
# I've implemented this to transform to list, but the result is not good
try:
int(group.replace('[', '').replace(']', ''))
val = [val]
except ValueError:
val = {group[1:-1]: val}
return {key: val}
def merge_two_structs(s1, s2):
if isinstance(s1, list) and \
isinstance(s2, list):
return s1 + s2
if isinstance(s1, dict) and \
isinstance(s2, dict):
retval = s1.copy()
for key, val in s2.iteritems():
if retval.get(key) is None:
retval[key] = val
else:
retval[key] = merge_two_structs(retval[key], val)
return retval
return s2
def merge_structs(structs):
if len(structs) == 0:
return None
if len(structs) == 1:
return structs[0]
first, rest = structs[0], structs[1:]
return merge_two_structs(first, merge_structs(rest))
def parse_form(pair_strings):
key_pairs = [parse_key_pair(x, pair_strings[x]) for x in pair_strings]
return merge_structs(key_pairs)
sample = {
'some': 'value',
'with': True,
'but[]': ['contains', 'also', 'some', 'array'],
'or[0]': 'even',
'or[1]': 'numbered',
'or[2]': 'arrays',
'also[0][some]': 'with',
'also[0][sub]': 'complex',
'also[0][values]': 'structure',
'and[finally]': 'some',
'and[easier]': 'ones'
}
print (json.dumps(parse_form(sample)))
如果您能帮助我了解如何获取列表而不是数组的字典,那将是完美的!
当然,如果已经有其他库可以很好地完成这项工作,我会全力以赴!
【问题讨论】:
标签: python post serialization deserialization