Как обойти массив JSON и записать данные в базу данных в 1С:Предприятие 8.3

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

В этой статье мы подробно разберем, как уйти от устаревших рекурсивных парсеров, строящих сложные деревья значений, и как быстро, эффективно и безопасно обработать входящий JSON-массив штатными средствами платформы 1С:Предприятие 8.3.

В чем сложность старых подходов к парсингу JSON?

В старых версиях платформы (до релиза 8.3.6) отсутствовала встроенная поддержка работы с JSON на уровне платформенных функций. Разработчикам приходилось использовать сторонние обработки, писать собственные рекурсивные алгоритмы (такие как упомянутые в обсуждении функции СформироватьДерево2) или использовать COM-объекты (например, Script Control). Эти методы имели ряд критических недостатков:

  1. Низкая скорость работы: обработка больших массивов на встроенном языке выполнялась в разы медленнее, чем это делают современные низкоуровневые средства платформы.
  2. Сложность кода: рекурсивные функции парсинга трудно читать, отлаживать и поддерживать.
  3. Нетипизированные структуры данных: вместо удобных коллекций 1С (таких как Массив и Структура) разработчики часто получали громоздкие деревья значений, обход которых требовал избыточного кода.

Современная платформа предоставляет программисту объект ЧтениеJSON и функцию ПрочитатьJSON(), которые выполняют всю черновую работу по десериализации за доли секунды.

Шаг 1. Чтение структуры JSON штатными средствами

Прежде чем приступать к записи данных в базу, нам необходимо преобразовать текстовую строку JSON в коллекцию, с которой умеет работать встроенный язык 1С. В нашем распоряжении есть массив клиентов items. Каждый клиент внутри этого массива представляет собой объект со свойствами customerId, firstName, phoneNumber и так далее.

Проанализируем имена свойств в исходном тексте. Поскольку ключи объектов в JSON не содержат недопустимых для переменных 1С символов (дефисов, пробелов, спецсимволов), мы можем прочитать их напрямую в штатный объект Структура. Если бы ключи содержали дефисы, нам пришлось бы читать их как Соответствие.

Рассмотрим пример кода для десериализации строки JSON:


// Предположим, что в переменной СтрокаJSON находится исходный текст ответа
СтрокаJSON = ХТТПЗапрос.ResponseText;

// Инициализируем объект чтения
ПотокЧтения = Новый ЧтениеJSON;
ПотокЧтения.УстановитьСтроку(СтрокаJSON);

// Выполняем десериализацию.
// Второй параметр "Ложь" указывает платформе преобразовывать объекты JSON в Структуры 1С.
// Если передать "Истина", объекты будут прочитаны как Соответствия.
ДанныеJSON = ПрочитатьJSON(ПотокЧтения, Ложь);

// Обязательно закрываем поток чтения данных
ПотокЧтения.Закрыть();

После выполнения данного фрагмента в переменной ДанныеJSON будет находиться объект типа Структура. У этой структуры будет единственное свойство — items, содержащее Массив, элементами которого являются вложенные структуры (наши клиенты).

Шаг 2. Организация цикла обхода массива данных

Теперь, когда данные преобразованы в коллекцию 1С, мы можем легко обойти их с помощью цикла Для Каждого. Нам нужно извлечь каждого клиента, проверить его существование в базе данных (чтобы избежать дублирования информации) и записать новые или обновленные сведения.

Давайте разберем по шагам, как построить надежный цикл для переноса данных в справочник ФизическиеЛица (или любой аналогичный справочник в вашей конфигурации, например, Контрагенты):


// Получаем массив клиентов из десериализованной структуры
МассивКлиентов = ДанныеJSON.items;

Для Каждого ТекущийКлиент Из МассивКлиентов Цикл
    
    // 1. Поиск существующего элемента в информационной базе.
    // Настоятельно рекомендуется осуществлять поиск по уникальному идентификатору внешней системы.
    // Для этого в справочнике должен быть создан реквизит, например, IDВнешний (тип: Число или Строка).
    СсылкаНаКлиента = Справочники.ФизическиеЛица.НайтиПоРеквизиту("IDВнешний", ТекущийКлиент.customerId);
    
    Если СсылкаНаКлиента.Пустая() Тогда
        // Создаем новый элемент, если клиент ранее не загружался
        ОбъектКлиента = Справочники.ФизическиеЛица.СоздатьЭлемент();
        ОбъектКлиента.IDВнешний = ТекущийКлиент.customerId;
    Иначе
        // Получаем существующий объект для редактирования/обновления полей
        ОбъектКлиента = СсылкаНаКлиента.ПолучитьОбъект();
    КонецЕсли;
    
    // 2. Заполнение базовых реквизитов
    // Обратите внимание на обработку значений Null. Об этом мы поговорим ниже.
    Если ТекущийКлиент.fullName <> Null Тогда
        ОбъектКлиента.Наименование = ТекущийКлиент.fullName;
    ИначеЕсли ТекущийКлиент.firstName <> Null Тогда
        ОбъектКлиента.Наименование = ТекущийКлиент.firstName;
    КонецЕсли;
    
    // Заполняем контактные данные
    Если ТекущийКлиент.phoneNumber <> Null Тогда
        ОбъектКлиента.Телефон = ТекущийКлиент.phoneNumber;
    КонецЕсли;
    
    // 3. Запись объекта в базу данных с обработкой возможных исключений
    Попытка
        ОбъектКлиента.Записать();
    Исключение
        // Логируем ошибку, чтобы один некорректный объект не прерывал загрузку всего массива
        ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
        ЗаписьЖурналаРегистрации("Интеграция.ЗагрузкаКлиентов",
            УровеньЖурналаРегистрации.Ошибка,
            Справочники.ФизическиеЛица,
            СсылкаНаКлиента,
            "Не удалось записать клиента с ID " + ТекущийКлиент.customerId + ". Ошибка: " + ТекстОшибки);
    КонецПопытки;
    
КонецЦикла;

Шаг 3. Обработка сложных типов данных и значений Null

При переносе данных из веб-сервисов во встроенный язык 1С важно учитывать специфику типизации JSON. Разберем ключевые моменты, с которыми вы обязательно столкнетесь:

Анализ значений типа Null. В формате JSON часто встречается значение null (например, "cardNumber": null). При десериализации платформа 1С преобразует его в системный тип Null. Попытка напрямую присвоить значение типа Null реквизитам с жестким типом (например, числу, строке или дате) вызовет системную ошибку или запишет некорректное значение. Перед записью всегда делайте явную проверку: Если ТекущееСвойство <> Null Тогда.

Обработка составных объектов дат. В предоставленном примере структура даты рождения передается вложенным объектом:


"birth": {
    "day": 24,
    "month": 3,
    "year": 1990
}

Для корректного преобразования этих данных в системную Дату в 1С мы должны проверить заполненность всех полей и собрать их с помощью конструктора даты:


// Проверяем наличие вложенной структуры birth
Если ТекущийКлиент.birth <> Неопределено И ТекущийКлиент.birth <> Null Тогда
    
    // Проверяем, что все составляющие даты переданы и заполнены
    Если ТекущийКлиент.birth.year <> Null 
        И ТекущийКлиент.birth.month <> Null 
        И ТекущийКлиент.birth.day <> Null Тогда
        
        Попытка
            ОбъектКлиента.ДатаРождения = Дата(ТекущийКлиент.birth.year, 
                                              ТекущийКлиент.birth.month, 
                                              ТекущийКлиент.birth.day);
        Исключение
            // Сработает, если переданы некорректные числа (например, 31 февраля)
            ЗаписьЖурналаРегистрации("Интеграция.ЗагрузкаКлиентов.ДатаРождения",
                УровеньЖурналаРегистрации.Предупреждение, , ,
                "Некорректный формат даты рождения у клиента ID: " + ТекущийКлиент.customerId);
        КонецПопытки;
        
    КонецЕсли;
КонецЕсли;

Конвертация строковых значений дат. Если дата передается в формате строки ISO 8601 (например, "registeredAt": "2018-05-26T23:27:45"), вы можете использовать встроенный платформенный метод преобразования. Для этого при вызове функции ПрочитатьJSON() можно передавать дополнительные параметры, которые автоматически преобразуют строки определенного формата в переменные типа Дата 1С.

Резюме

Отказ от кастомных рекурсивных парсеров в пользу встроенного объекта ЧтениеJSON и функции ПрочитатьJSON() позволяет писать более простой, лаконичный и быстродействующий код. Использование циклов типа Для Каждого в сочетании с предварительным поиском дублей в базе данных и проверкой полей на значение Null гарантирует стабильность работы интеграции и чистоту ваших данных.

← На главную