Как правильно передать список XDTO в параметр веб-сервиса в 1С

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

Работа с веб-сервисами в 1С через механизм XDTO (XML Data Transfer Objects) часто вызывает затруднения у разработчиков, особенно когда речь идет о передаче сложных структур, содержащих вложенные списки или массивы. Типичная ошибка, с которой сталкиваются программисты: "Значение не может быть установлено свойству, имеющему объектный тип". Эта ошибка возникает в тот момент, когда мы пытаемся присвоить свойству родительского объекта целый массив или список одним махом.

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

Анализ проблемы: почему возникает ошибка объектного типа

Рассмотрим ситуацию, когда в схеме XML (WSDL-описании сервиса) определен тип, содержащий свойство с признаком maxOccurs="unbounded". В объектной модели 1С такое свойство представляется не просто как переменная, а как специальный объект — СписокXDTO. Главная особенность заключается в том, что при создании родительского объекта этот список инициализируется автоматически (хотя и остается пустым).

Разберем типичный ошибочный код, который приводит к сбою:


// ОШИБОЧНЫЙ ПОДХОД
WSПараметр = Сервис.ФабрикаXDTO.Создать(ТипПараметра);
WSСписокНаград = Сервис.ФабрикаXDTO.Создать(ТипСпискаНаград); // Попытка создать отдельный список

Пока Выборка.Следующий() Цикл
    НоваяНаграда = Сервис.ФабрикаXDTO.Создать(ТипНаграды);
    // ... заполнение свойств награды ...
    WSСписокНаград.Добавить(НоваяНаграда);
КонецЦикла;

// В этой строке возникнет ошибка "Значение не может быть установлено свойству..."
WSПараметр.Awards = WSСписокНаград; 

Проанализируем причину: свойство Awards уже существует внутри WSПараметр как готовый объект типа СписокXDTO. Платформа 1С не позволяет заменить этот внутренний объект другим объектом, созданным отдельно. Вместо присваивания (=) мы должны обращаться непосредственно к существующему свойству и добавлять элементы прямо в него.

Решение №1: Прямое наполнение списка через метод Добавить()

Самый надежный и правильный способ работы с коллекциями XDTO — это последовательное добавление элементов в уже существующее свойство родительского объекта. Давайте перепишем алгоритм правильно. Мы не будем создавать промежуточный объект-массив, а будем работать с коллекцией Awards напрямую.

Рассмотрим по шагам правильную последовательность действий:

  1. Создаем основной объект-контейнер (параметр веб-сервиса) через ФабрикаXDTO.Создать().
  2. Определяем тип вложенного элемента (в нашем примере это тип самой "Награды").
  3. В цикле создаем каждый элемент награды.
  4. Добавляем созданный элемент в свойство родителя, используя метод Добавить().

Посмотрим на пример реализации:


// 1. Создаем корневой объект запроса
WSПараметр = СервисSharepoint.ФабрикаXDTO.Создать(ТипЗапроса);

// 2. Получаем типы данных для создания вложенных элементов
ТипWSAward = СервисSharepoint.ФабрикаXDTO.Тип("http://your-namespace.com", "Award");

// 3. Организуем цикл по данным (например, выборка из БД)
Если Не ВыборкаДетальныеЗаписи.Количество() = 0 Тогда
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        
        // Создаем объект отдельной награды
        WSПараметрAward = СервисSharepoint.ФабрикаXDTO.Создать(ТипWSAward);
        WSПараметрAward.Date = ДатаДляSharePoint(ВыборкаДетальныеЗаписи.ДатаПриказа);
        WSПараметрAward.Name = XMLСтрока(ВыборкаДетальныеЗаписи.Награда);
        
        // ВАЖНО: Добавляем созданный объект прямо в свойство родителя
        // Обратите внимание: мы не используем "=", мы используем метод ".Добавить()"
        WSПараметр.Awards.Добавить(WSПараметрAward);
        
    КонецЦикла;
КонецЕсли;

// Теперь объект WSПараметр готов к отправке в веб-сервис

Решение №2: Использование СериализаторXDTO для сложных структур

Если структура данных в 1С (например, массив структур) полностью соответствует схеме XDTO, можно воспользоваться объектом СериализаторXDTO. Этот метод позволяет автоматизировать процесс, если вам не хочется вручную перебирать каждое поле в цикле. Однако этот способ требует строгого соответствия имен ключей в структуре 1С именам свойств в XDTO.

Разберем ситуацию: у нас есть массив структур в 1С, и мы хотим быстро превратить его в объект XDTO.


// Предположим, у нас есть МассивНаград, где каждый элемент - Структура
МассивНаград = Новый Массив;
Для Каждого Строка Из ТаблицаДанных Цикл
    ДанныеНаграды = Новый Структура("Date, Name", Строка.Дата, Строка.Наименование);
    МассивНаград.Добавить(ДанныеНаграды);
КонецЦикла;

// Вместо ручного создания XDTO-объектов, используем сериализатор
// Но помните, что это сработает, если типы в схеме позволяют такую трансформацию
ОбъектXDTO_Awards = СериализаторXDTO.ЗаписатьXDTO(МассивНаград);

Важное замечание: Использование сериализатора удобно для простых преобразований, но при работе с веб-сервисами SharePoint или сложными корпоративными шинами данных (ESB) ручное создание объектов через ФабрикаXDTO считается более "прозрачным" и менее подверженным ошибкам типизации.

Особенности инициализации промежуточных узлов

Иногда структура XDTO подразумевает наличие "обертки" над списком. Например, свойство Awards — это не сам список, а объект типа ArrayOfAward, у которого внутри есть свойство Award, являющееся списком. В этом случае алгоритм усложняется на один уровень вложенности.

Выясним причину ошибки в таких случаях: если свойство Awards имеет объектный тип (обертка), оно может быть Неопределено при создании родителя. Тогда его нужно создать явно.

Проанализируем пример со вложенной оберткой:


// Создаем родительский объект
WSПараметр = Сервис.ФабрикаXDTO.Создать(ТипWSRequest);

// Если Awards - это сложный тип-обертка (например, ArrayOfAward)
// Сначала создаем саму обертку
ТипОбертки = Сервис.ФабрикаXDTO.Тип("http://namespace", "ArrayOfAward");
ОбъектОбертка = Сервис.ФабрикаXDTO.Создать(ТипОбертки);

// Теперь наполняем список ВНУТРИ обертки
Пока Выборка.Следующий() Цикл
    Элемент = Сервис.ФабрикаXDTO.Создать(ТипWSAward);
    Элемент.Name = "За заслуги";
    
    // Добавляем в свойство Award, которое является списком внутри обертки
    ОбъектОбертка.Award.Добавить(Элемент);
КонецЦикла;

// И только теперь присваиваем ПОЛНОСТЬЮ заполненную обертку родительскому свойству
// Это сработает, так как Awards - это НЕ список, а ОДИНОЧНЫЙ объект-обертка
WSПараметр.Awards = ОбъектОбертка;

Как проверить тип свойства в отладчике

Чтобы точно понять, использовать ли .Добавить() или =, воспользуйтесь отладчиком 1С:

Правильное понимание разницы между списком и объектом в XDTO — ключ к успешной интеграции с любыми внешними системами. Использование метода Добавить() для коллекций является стандартом разработки в среде 1С:Предприятие 8.

← На главную