Реструктуризация объекта, который был сериализован на jQuery.параметр в Python


Я пытаюсь восстановить комплексные данные сериализованы с помощью библиотеки jQuery.параметр (функция).

Я сделал то, что, кажется, работает, но мне было бы любопытно, если у вас есть способы улучшить этот код.

Образец структура выглядит следующим образом:

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[1][values]': 'structure',
    'and[finally]': 'some',
    'and[easier]': 'ones'
}

Разбирается через 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%5B1%5D%5Bvalues%5D=structure&and%5Bfinally%5D=some&and%5Beasier%5D=ones"

Вот следующий код, начиная с этого пакета, который выполняет следующие действия:

  • Преобразует строку запроса обратно в объект
  • Преобразует любую булеву/инт/JSON в их формате
  • Уважение в лучшем случае на заказ в списках, ожидая, что цифры увеличиваются корректно (прыжок с индекса 1 до индекса 4 не будет работать, и будет ставить указатель 4 в 2)

Любопытно узнать ваше мнение :

#!/usr/bin/python
# -*- coding: utf-8 -*-

import re, json, six
from six import string_types


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:
                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 six.iteritems(s2):
            if retval.get(key) is None:
                retval[key] = val
            else:
                retval[key] = merge_two_structs(retval[key], val)
        return retval
    return s2


def convert_to_list(items):
    if not isinstance(items, dict):
        return items

    retval = items.copy()
    for key, val in six.iteritems(items):
        if isinstance(val, dict):
            val = convert_to_list(val.copy())

        try:
            index = int(key)
            if not isinstance(retval, list):
                retval = []
            if len(retval) > index:
                retval[index] = val
            else:
                retval.append(val)
        except ValueError:
            retval[key] = val

    return retval


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]
    result = merge_structs(key_pairs)
    return convert_to_list(result)


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)

У меня было очень трудное время, пытаясь заставить его работать. Я хотел сделать все в один цикл, но это был слишком сложный (по крайней мере для меня).

В convert_to_list() может быть размещен непосредственно внутри merge_two_structs но я не нашел хороший способ, чтобы заставить его работать.

Это хороший exercice чтобы манипулировать рекурсия :)



89
0
задан 29 марта 2018 в 01:03 Источник Поделиться
Комментарии