1. Вступайте в наш Telegram чат: https://t.me/a_parser Нас уже 2600+ и мы растем!
    Скрыть объявление

Обзор вариантов вывода результатов в JSON виде

Полный обзор существующих способов вывода результатов в JSON

Метки:
  1. Support
    Вопросы о выводе результатов в JSON являются довольно частыми среди всех обращений в Техническую поддержку. Поэтому мы подготовили небольшой обзор всех возможных способов это сделать.
    В качестве "подопытного" возьмем парсер Google подсказок SE::Google::Suggest SE::Google::Suggest. Также для большей наглядности условимся что в результате нам необходимы сам запрос, кол-во подсказок по нему, непосредственно сами подсказки и количество символов в каждой подсказке (ее длина).

    1. Вывод в JSON для одиночных запросов
    Простейший вариант вывода в JSON - это использование метода шаблонизатора .json:
    Код:
    [% obj = {};
    obj.query = query;
    obj.count = p1.totalcount;
    obj.suggests = [];
    
    FOREACH item IN p1.results;
        obj.suggests.push({
            keyword = item.suggest
            length = item.suggest.length
        });
    END;
    
    obj.json %]
    Здесь мы в Общем формате результата создаем пустой объект obj, записываем в него две переменные (запрос query и кол-во результатов по нему count) и пустой массив suggests. После чего наполняем массив объектами, содержащими подсказку keyword и кол-во символов в ней length. Тем самым получается нужная структура. И выводим это все в виде JSON строки:
    Код:
    {"suggests":[{"keyword":"testzentrum","length":11},{"keyword":"teste dich","length":10},{"keyword":"testosterone","length":12},{"keyword":"testzentrum in der nähe","length":23},{"keyword":"testosteron","length":11},{"keyword":"testdaf","length":7},{"keyword":"test center near me","length":19},{"keyword":"testament","length":9}],"count":8,"query":"test"}
    Этот способ отлично подходит для одиночных запросов, например через API метод oneRequest.

    2. Формирование JSON построчно
    Но что будет, если в предыдущем случае подать на вход несколько запросов? Проверим, добавив для удобства перевод строки после вывода JSON. И попробуем поработать с полученным JSON'ом, вставив его в любой редактор JSON:
    [​IMG]
    Как видно на скриншоте, мы получили ошибку, т.к. JSON не валиден. Сейчас это по сути набор строк, который не отвечает правилам JSON.

    Самым очевидным решением по формированию валидного JSON'а для нескольких запросов (да и в целом для любого количества больше одного) является использование массива. Если посмотреть на любой массив в JSON, то он похож на строки, разделенные запятыми. И все это взято в квадратные скобки. Что ж, добавим к выводу запятые (вместе с переводом строки, в формате результата) и квадратные скобки в самом начале и конце (воспользуемся для этого функционалом Начального и Конечного текстов).

    Код шаблона в Формате результата по сути остается такой же, как и предыдущем примере, только добавляется запятая после каждой строки (и перевод строки для удобства):
    Код:
    obj.json _ ",\n"
    Начальный и Конечный тексты:
    [​IMG]
    Получаем такой результат:
    [​IMG]
    Как видим, снова ошибка:(
    Если изучить то, что получилось - становится понятно, что все портит запятая в самом конце (на скрине выделена стрелкой). Но она выводится вместе со строкой JSON'а и нет возможности указать парсеру что какая-то строка последняя и запятую выводить не нужно...

    Вполне неплохим решением в этой ситуации будет добавление пустого объекта в самый конец. Для этого просто пропишем его в Конечном тексте.
    [​IMG]
    Теперь, если запустить пресет, получим валидный JSON в виде массива объектов, где каждый объект - это данные по каждому запросу.
    [​IMG]
    При дальнейшей обработке пустой объект можно просто игнорировать.

    2.1. Избавляемся от пустого обьекта
    Но как быть, если по какой-то причине пустой объект в конце недопустим? Существует небольшой лайфхак. Надо немного изменить логику построчного формирования и выводить запятую не в конце каждой строки, а в начале. И нужно завести переменную, которая будет играть роль флага, указывающего ставить ли запятую или нет. В примере ниже это переменная notFirst.
    Итого шаблон для Формата результата будет выглядеть так:
    Код:
    [% IF notFirst;
        ",\n";
    ELSE;
        notFirst = 1;
    END;
    
    obj = {};
    obj.query = query;
    obj.count = p1.totalcount;
    obj.suggests = [];
    
    FOREACH item IN p1.results;
        obj.suggests.push({
            keyword = item.suggest
            length = item.suggest.length
        });
    END;
    
    obj.json %]
    Не забудьте убрать пустой объект из Конечного текста.
    В результате получаем валидный JSON без пустых объектов.
    Данный метод не имеет никаких ограничений по кол-ву запросов и объёму результатов. Его вполне можно использовать для любых задач, требующих вывод в JSON.
    Но существует еще один способ и о нем ниже.

    3. Формирование объекта в памяти и вывод результатов в JSON в конце работы задания
    Выше мы для нескольких запросов выводили данные в массив. Но как быть, если по какой-то причине массив нам не подходит и нужен один большой объект? И чтобы ключами в этом объекте были подаваемые на вход запросы...
    Решение есть. Нужно создать в самом начале работы задания пустой объект, писать в него данные по ходу парсинга и в конце работы задания вывести все это в результат. Поможет все это реализовать опять же функционал Начального и Конечного текстов. Как известно, Начальный отрабатывает в самом начале работы задания, а Конечный - в конце. Этим и воспользуемся.

    Итак, в Начальном тексте пропишем создание пустого объекта (используя шаблонизатор):
    Код:
    [% obj = {} %]
    В Общем формате результата пропишем запись в этот объект:
    Код:
    [% obj.${query} = {};
    obj.${query}.count = p1.totalcount;
    obj.${query}.suggests = [];
    
    FOREACH item IN p1.results;
        obj.${query}.suggests.push({
            keyword = item.suggest
            length = item.suggest.length
        });
    END %]
    И в Конечном тексте пропишем вывод в JSON:
    Код:
    [% obj.json %]
    Запускаем и получаем JSON в требуемом виде:
    [​IMG]
    Код:
    eJxtVN9v2jAQ/lcii0qtVEWt2r1k2gNlsHVi0EL7BDx45JIaHDuzHboqyv++OwcS
    QnmxfHff/fjuzi6Z43ZrnwxYcJZFi5Ll/s4iFkPCC+nYNcu5sWDIvGDzYRT90DqV
    EEXzIk3BEuKAXa2uGfrj1Y60yTjFWVwE+s8m7JV/CzAfVfAtKKuvS3WsC9e6UA4t
    +W3otOPSy6cgW6eziFus0LhUo+ls2B/8DISDLHickPs+O5ndWe8wL+zbZUn2pdvC
    x7s2MUakEAdMbZOgUvd2YgprLSGqK0wynHwPLlasYT3nO3jRyDoRElr1CKUJzwAN
    vZg7IGuY+A5dXoXuH/WQx7FwQisu69ZRv9t2viqBRNBfacQSJwF2ZHSGKgc+gCd6
    aPuC9bzMMEThfZ9rHxYlXFq4ZhZLHXEsJD61IGHDnTbTnOpBfcm06ks5hh3IFubj
    PxRCxrgc/QSdHveO5yHTTzGqht5xqh2Yd4M1NFG89DD93XrFeqzTQzOkyIRD2Q5o
    a1B7g8otQN70bEKwTBto0jhTQJMc1z8HFTe76le0M9Z+3gGEG6tVDegw7Eysq1xr
    lYh0ityMiOGALNQLvr+pGugsl0CUVSElTszCrN2cvt1PiISmK5+cBz5F5+U6raX9
    NUcdPWMjcDO/UIEZNvk46z7kmkv5OhsfW1i7bX7T6HXU/wG+geLm/i7xJ/jz7uh+
    708axRoXPtW4isi5WjXfSfPplGc/laiscNAb+1SjiTphUYc9tDhFFt1W/wG6160c
    
    Благодаря хранению данных в памяти, можно дополнительно перед выводом в результат произвести с ними различные действия. К примеру отсортировать или произвести подсчет какой-то статистики. Кроме этого данный метод более удобен для логического понимания его работы, в отличие от вышеописанного построчного вывода, который является несколько нетипичным вариантом формирования JSON. Но у этого варианта есть один существенный минус. Его нельзя использовать для очень больших объёмов запросов, т.к. из-за хранения всех данных в памяти можно попросту упереться в ее нехватку. Также итоговый вывод или пост-обработка собранных результатов на большом количестве запросов может занять много времени и привести к ошибкам в работе А-Парсера.


    В этой статье мы рассмотрели все варианты вывода результатов в JSON. Какой использовать - зависит от решаемых задач. Оптимальным является построчный вывод, но если нужно сделать какую-то пост-обработку собранных результатов "на лету" - то лучше использовать 3-й метод.
    Evgeniy.O нравится это.