【问题标题】:jQuery.param unserialization in PythonPython中的jQuery.param反序列化
【发布时间】: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


    【解决方案1】:

    上面的代码有问题。

    request.form.to_dict() 没有正确表示通过"item[]=XXX&item[]=YYY" 传递的项目。你只会得到一个item[]...

    所以为了解决这个问题,我将to_dict() 改写为:

    from six import string_types
    
    def convert_val(val):
        if not isinstance(val, string_types):
            return val
        elif val == '':
            return None
        elif val.lower() in ('false', 'true'):
            return True if val.lower() == 'true' else False
        if val[0:1] == '{':
            try:
                return json.loads(val)
            except ValueError:
                pass
    
        try:
            return int(val)
        except ValueError:
            return val
    
    
    def request_to_dict(params):
        result = {}
        for k in params:
            items = params.getlist(k)
            if len(items) == 1:
                result[k] = convert_val(items[0])
            else:
                result[k] = items
    
        return parse_form(result)
    

    这会返回一个正确的字典来解析上述示例的特性,尽可能保持类型(布尔值、整数、json、列表或字符串),并且与 Python 2 和 3 兼容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-29
      • 1970-01-01
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      相关资源
      最近更新 更多