Как в 1С 7.7 парсить JSON с помощью SQLite и правильно определять булевы значения?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При работе с API и обмене данными в 1С 7.7 часто возникает задача парсинга JSON. Встроенных средств для этого в платформе нет, а сторонние парсеры могут не справляться с большими объемами данных и приводить к падению программы. Отличной альтернативой является использование внешней компоненты SQLite, которая позволяет обрабатывать даже очень большие JSON-файлы прямо в памяти.

Однако при таком подходе возникает неочевидная проблема: SQLite по умолчанию преобразует булевы значения true и false из JSON в числа 1 и 0. Это создает неоднозначность: как отличить логическое "Да" (true), ставшее единицей, от числового значения 1? Особенно это критично, когда структура JSON динамическая и заранее неизвестно, какие поля являются логическими, а какие — числовыми.

Рассмотрим, как решить эту проблему элегантно и надежно, используя возможности самой SQLite.

Начальный этап: парсинг JSON с помощью функции json_tree

Для начала убедимся, что у нас есть современная версия внешней компоненты 1sqlite.dll, так как функции для работы с JSON появились в более свежих сборках. Основная работа по разбору JSON ложится на табличную функцию json_tree.

Она принимает на вход текстовую строку с JSON и возвращает таблицу, в которой каждый узел JSON-документа представлен отдельной строкой. Это позволяет работать с JSON как с обычной таблицей с помощью SQL-запросов.

Вот пример базовой функции на 1С 7.7 для парсинга JSON в ТаблицуЗначений:


Функция РазборJSON_SQLLite(ТекстJSON)
  Попытка
        База = СоздатьОбъект("SQLiteBase");
    Исключение
        ЗагрузитьВнешнююКомпоненту("1sqlite.dll");
        База = СоздатьОбъект("SQLiteBase");
    КонецПопытки;
    
    // Открываем базу данных в оперативной памяти
    База.Открыть(":memory:");
    
    Запрос = База.НовыйЗапрос();
    Запрос.Подготовить("
    |SELECT
    |    *
    |FROM json_tree(@ТекстJSON)
    |");
    Запрос.УстановитьПараметр("@ТекстJSON", ТекстJSON);
    
    тзДерево = Запрос.Выполнить();
    Возврат тзДерево;    
КонецФункции

Выполнив этот код, мы получим таблицу со всеми элементами JSON, но столкнемся с описанной выше проблемой: все значения true будут представлены как 1.

Ключ к решению: колонка "type"

Секрет правильного определения типов данных кроется в структуре таблицы, которую возвращает функция json_tree. В современных версиях SQLite она содержит не только ключ (key) и значение (value), но и, что самое важное, колонку с типом данных (type).

Эта колонка для каждой строки явно указывает на исходный тип значения в JSON. Возможные значения в ней:

Имея эту информацию, мы можем легко отличить логическую единицу от числовой. Если в колонке value стоит 1, а в колонке type — 'true', значит, это было булево значение. Если же в type стоит 'integer', то это обычное число.

Финальное решение: преобразуем типы на лету с помощью SQL-запроса

Можно было бы получать таблицу с колонкой type в 1С и уже в коде анализировать ее, преобразуя значения. Но есть способ лучше — сделать всю работу по преобразованию прямо в SQL-запросе с помощью оператора CASE. Это и производительнее, и делает код в 1С чище.

Модифицируем наш запрос так, чтобы он сразу возвращал готовые к использованию данные: "Да" для true, "Нет" для false, и исходное значение для всех остальных типов.

Посмотрим на финальный код функции:


Функция РазборJSON_SQLLite(ТекстJSON)
    Попытка
        База = СоздатьОбъект("SQLiteBase");
    Исключение
        ЗагрузитьВнешнююКомпоненту("1sqlite.dll");
        База = СоздатьОбъект("SQLiteBase");
    КонецПопытки;
    
    База.Открыть(":memory:");
    Запрос = База.НовыйЗапрос();
    
    Запрос.Подготовить("
    |SELECT
    |    -- Используем оператор CASE для преобразования значений
    |    CASE
    |        WHEN tree.type == 'true' THEN 'Да'
    |        WHEN tree.type == 'false' THEN 'Нет'
    |        ELSE tree.value
    |    END AS Значение,
    |    tree.key AS Ключ,
    |    tree.path AS Путь,
    |    tree.type AS Тип
    |FROM json_tree(@ТекстJSON) AS tree
    |WHERE tree.key > '' // Отбираем только узлы с непустыми ключами
    |");
    
    Запрос.УстановитьПараметр("@ТекстJSON", ТекстJSON);  
    тзДерево = Запрос.Выполнить();
    
    Возврат тзДерево;    
КонецФункции

Что делает этот запрос:

  1. CASE ... END AS Значение: Создает вычисляемую колонку "Значение".
  2. WHEN tree.type == 'true' THEN 'Да': Если тип данных — 'true', в колонку "Значение" записывается строка "Да".
  3. WHEN tree.type == 'false' THEN 'Нет': Если тип — 'false', записывается "Нет".
  4. ELSE tree.value: Во всех остальных случаях в колонку "Значение" записывается исходное значение из колонки value.

Теперь в результате мы получаем ТаблицуЗначений, где булевы значения уже представлены в удобном для пользователя виде, а числовые значения остались числами. Проблема решена полностью и очень эффективно.

Этот метод отлично зарекомендовал себя при работе с большими объемами данных, например, при получении ответов от API "Честный Знак", где размер JSON-ответа может достигать нескольких мегабайт. SQLite обрабатывает такие объемы практически мгновенно, не вызывая падения 1С.

← На главную