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