Интеграция с внешними веб-сервисами (например, сервисами ВетИС/Меркурий, маркировки «Честный Знак» или логистических операторов) — частая задача при разработке на платформе 1С. При разборе сложных ответов программисты регулярно сталкиваются с ситуацией, когда часть входящих структур не содержит определенных полей либо данные не сохраняются в строки табличной части. Проанализируем типичные причины таких ошибок и разберем надежные методы их устранения.
Рассмотрим типовой сценарий: выполняется запрос к веб-сервису, возвращающий список документов или партий. При обходе элементов коллекции заполняются реквизиты строки табличной части. Проблема возникает на строках с многоуровневым обращением через точку к необязательным (опциональным) полям схемы XDTO или структуры:
стр.UUIDУпаковки = ДеталиСтроки.packingList.packingForm.UUID;
Если в схеме сервиса узел packingList объявлен как необязательный, то при его отсутствии попытка прочитать вложенное свойство packingForm немедленно вызывает критическую ошибку «Поле объекта не обнаружено» или «Попытка обращения к свойству несуществующего объекта».
Ошибочной практикой является попытка проверить заполненность строки табличной части с помощью конструкции Если ЗначениеЗаполнено(стр) Тогда. Новая строка таблицы, созданная методом Остатки.Добавить(), всегда является валидной ссылкой на строку (объект СтрокаТабличнойЧасти), поэтому такое условие всегда возвращает Истина и не защищает от ошибки при обращении к свойствам входящих данных.
Разберем вариант, когда тип входящего объекта не позволяет заранее проверить состав полей простым методом. Если поместить всю группу присвоений в один общий блок Попытка ... Исключение, при первой же ошибке платформа прервет выполнение всего блока и пропустит остальные корректные поля. Поэтому критичные строки необходимо изолировать:
Попытка
стр.UUIDУпаковки = ДеталиСтроки.packingList.packingForm.UUID;
Исключение
стр.UUIDУпаковки = "";
КонецПопытки;
Попытка
стр.ДолжностьВетВрача = СтрокаВСД.confirmedBy.post;
Исключение
стр.ДолжностьВетВрача = "";
КонецПопытки;
Такой подход гарантирует, что отсутствие одного опционального свойства не помешает заполнению остальных реквизитов строки.
Чтобы не загромождать код десятками блоков Попытка ... Исключение, создадим компактную вспомогательную функцию. Посмотрим, как реализовать безопасное извлечение значения свойства:
Функция ПолучитьЗначениеБезопасно(Объект, ИмяСвойства, ЗначениеПоУмолчанию = Неопределено)
Попытка
Возврат Объект[ИмяСвойства];
Исключение
Возврат ЗначениеПоУмолчанию;
КонецПопытки;
КонецФункции
Используем эту функцию для последовательного спуска по иерархии объектов:
Упаковка = ПолучитьЗначениеБезопасно(ДеталиСтроки, "packingList");
Если Упаковка <> Неопределено Тогда
ФормаУпаковки = ПолучитьЗначениеБезопасно(Упаковка, "packingForm");
Если ФормаУпаковки <> Неопределено Тогда
стр.UUIDУпаковки = ПолучитьЗначениеБезопасно(ФормаУпаковки, "UUID", "");
КонецЕсли;
КонецЕсли;
Если ответ десериализован в коллекцию типа Структура, используем встроенный метод Свойство():
Если ДеталиСтроки.Свойство("packingList") И ДеталиСтроки.packingList <> Неопределено Тогда
Если ДеталиСтроки.packingList.Свойство("packingForm") И ДеталиСтроки.packingList.packingForm <> Неопределено Тогда
стр.UUIDУпаковки = ДеталиСтроки.packingList.packingForm.UUID;
КонецЕсли;
КонецЕсли;
Если работа ведется напрямую с объектами ОбъектXDTO, состав доступных свойств проверяется через свойства типа XDTO:
Если ДеталиСтроки.ТипXDTO.Свойства.Получить("packingList") <> Неопределено
И ДеталиСтроки.packingList <> Неопределено Тогда
стр.UUIDУпаковки = ДеталиСтроки.packingList.packingForm.UUID;
КонецЕсли;
Нередко возникает ситуация, когда при отладке в окне «Вычислить выражение» значение переменной отображается корректно, однако в строке табличной части колонка остается пустой. Выясним причину этого поведения:
Число или ссылку на справочник), а из сервиса передается строковый GUID без преобразования, платформа 1С не сможет выполнить неявное приведение и очистит поле.Строка(10), а записывается идентификатор длиной 36 символов, значение может обрезаться или вызывать некорректное отображение.2023-11-20T14:30:00) требуют явного преобразования в тип Дата с помощью функций разбора XML-дат или функции XMLЗначение(Тип("Дата"), ...).Обратим внимание на частую ошибку производительности при заполнении табличной части — многократный вызов методов поиска внутри цикла:
// Неоптимальный код: порождает отдельный запрос к СУБД на каждой итерации
стр.Продукция = Справочники.ОписаниеПродукцииВетис.НайтиПоРеквизиту("GUID", Строка(ДеталиСтроки.product.guid));
При обработке сотен строк такой код существенно замедляет работу. Разберем правильный алгоритм пакетной выборки данных:
ГДЕ GUID В (&МассивИдентификаторов).Соответствие, где ключом будет GUID, а значением — ссылка на элемент справочника.стр.Продукция = СоответствиеСсылок.Получить(КлючGUID);.Применение безопасного чтения свойств в сочетании с корректной настройкой типов колонок и пакетными запросами обеспечивает стабильную и быструю обработку любых входящих пакетов данных из веб-сервисов.