amarao (amarao_san) wrote,
amarao
amarao_san

json4shell

Спасибо No Way с 2ch'а, я чуть не выкинул jsonstream, хотя это то, что мне нужно.

Он даже умеет стекированный json (это когда один json сразу после другого).

Осталось две проблемы: обработка невалидного json'а (я отложу это чуть на потом)... Пока что идея простая - мы будем обворачивать входной поток в "резервную" скобку, так что обрывок json'а покажется массивом. Или объектом? Надо думать. Список интереснее.

Вторая проблема: как понять, что из надёрганных из потока пар пока делать итерацию? Основная проблема состоит в том, в каком формате yield'дятся значения.

Выглядит это так:

[
    {"a1":"11","a2":"12","a3":"13" },
    {"a1":"21","a2":"22","a3":"23" },
    {"a1":"31","a2":"32","a3":"33" }
]


Нам выдают значения в следующем виде:
((), [])
((0,), {})
((0, u'a1'), u'11')
((0, u'a2'), u'12')
((0, u'a3'), u'13')
((1,), {})
((1, u'a1'), u'21')
((1, u'a2'), u'22')
((1, u'a3'), u'23')
((2,), {})
((2, u'a1'), u'31')
((2, u'a2'), u'32')
((2, u'a3'), u'33')

То есть нет "закрывающего тега". Мы можем заняться синтетикой и имитировать наличие закрывающего тега по одному из двух признаков:

1. анонсирован объект того же уровня глубины или выше, как и наш. Поскольку сам анонс нам ни холодно ни жарко, то мы его можем "съесть"... Хотя при этом, наверное, assemble не сработает. В любом случае, можно написать буфферизованный врапер-итератор над потоком, куда можно "развидеть" элемент.
2. Мы получили StopIteration

Оба хорошо ложатся на модель "итератор с реверсивным ходом и буфером".

ТО есть схема такая:

На входе у нас поток анонсов от JSONStream. Специальный хитропопый итератор, принимает на вход такой простой итератор. Но yield'ит он только "готовый субоъект", то есть, например, словарь как элемент списка". Когда yield'ить он знает, если вычитал лишку, кладёт в свой буфер.

То есть (опуская детали):

def buff_iter(j_iter):
    buf=[]
    while пока_не_хватит:
        n=j_iter.next()
        if n == обычный объект:
            buf.append(n)
        elif n == новый_объект_или_конец:
            yield assemble(buf)
            buf= list(n)


Где-то тут будет ещё обработка внешних вложенностей, хотя я прихожу к мысли, что если приспичит, то выковырять с помощью jq или соответствующей специальной программы, а наш json-iterate должен работать с входным списком или стекированным json'ом. Надо ли работать с dict'ом я даже и не знаю. В принципе, если игнорировать существование ключей, то можно и пофигу...

UPD: нашаманил, очень грубо, вот такое:

На вход получает либо массив объектов, либо стопку объектов, на выходе - питоновские объекты для итерирования. Вложенные словари/объекты пока не делал, меня больше идея интересует.

https://github.com/amarao/json4shell/tree/jsonstream/tools

./run sample_data для результатов.
Tags: json4shell
Subscribe

  • ceph + jq

    Они няшки и волшебство. ceph pg dump -f json|jq '.pg_stats[].acting[]'|sort -hu dumped all in format json 0 1 2 3 7 8 9 11 Подробности:…

  • чудеса апстрима

    Сегодня ночью отсылаю багрепорт, просыпаюсь, проблема решена. Итого: 1.8Гб json, 5Мб памяти на парсинг, константно. Но скорость в 1Мб/с парсинга…

  • JSONStream

    Внезапно, я погорячился. Простейший эксперимент со stacked json показывает, что он нифига не stateless и нифига не константный по памяти. Поток…

  • Post a new comment

    Error

    default userpic

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments