Как заполнить вложенные свойства XDTO, если тип определен внутри элемента (анонимный тип)?

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

Работа с XDTO-пакетами в 1С часто сопровождается трудностями, когда мы сталкиваемся с так называемыми анонимными типами. В интерфейсе конфигуратора они отображаются как «Определение типа». Главная проблема заключается в том, что к такому типу невозможно обратиться напрямую через ФабрикаXDTO.Тип(), так как у него нет глобального имени в пространстве имен схемы. Рассмотрим, как правильно пробираться сквозь иерархию таких объектов и заполнять их данные.

Почему возникает «Определение типа» и в чем сложность?

Проанализируем структуру XML-схемы (XSD). Если в схеме complexType описан не как самостоятельный именованный объект, а вложен напрямую внутрь элемента element, он становится анонимным. Для 1С это означает, что тип жестко привязан к конкретному свойству родителя. Чтобы создать такой объект, нам нужно сначала «спросить» у родительского свойства, какой тип оно ожидает, и только потом использовать этот тип для создания нового экземпляра через фабрику.

Способ 1: Последовательное создание объектов через метаданные свойств

Рассмотрим пошагово, как программно заполнить структуру, описанную автором темы. Нам нужно добраться до свойства Id, которое находится на четвертом уровне вложенности. Мы не можем просто присвоить строку свойству, если оно само является объектом. Нам нужно создать каждый промежуточный узел.

Разберем пример кода, который решает задачу через обращение к коллекции Свойства():


// 1. Создаем корневой объект
ТипКорня = ФабрикаXDTO.Тип("http://www.example.com/insurer", "insurer_id_t");
ОбъектКорня = ФабрикаXDTO.Создать(ТипКорня);

// 2. Добираемся до InsurerId
СвойствоInsurerId = ОбъектКорня.Свойства().Получить("InsurerId");
ОбъектInsurerId = ФабрикаXDTO.Создать(СвойствоInsurerId.Тип);

// 3. Добираемся до CmbndId
СвойствоCmbndId = ОбъектInsurerId.Свойства().Получить("CmbndId");
ОбъектCmbndId = ФабрикаXDTO.Создать(СвойствоCmbndId.Тип);

// 4. Добираемся до ClrSysMmbId
СвойствоClrSysMmbId = ОбъектCmbndId.Свойства().Получить("ClrSysMmbId");
ОбъектClrSysMmbId = ФабрикаXDTO.Создать(СвойствоClrSysMmbId.Тип);

// 5. Заполняем конечное значение
ОбъектClrSysMmbId.Id = "ТребуемоеЗначение";

// 6. Собираем матрешку обратно
ОбъектCmbndId.ClrSysMmbId = ОбъектClrSysMmbId;
ОбъектInsurerId.CmbndId = ОбъектCmbndId;
ОбъектКорня.InsurerId = ОбъектInsurerId;

В этом примере мы используем объект СвойствоXDTO, чтобы вытащить Тип, который платформа назначила этому свойству «по месту». Это универсальный способ, который работает даже с самыми запутанными схемами.

Способ 2: Оптимизированное создание через метод СоздатьОбъект()

Существует более лаконичный и быстрый способ, который часто упускают из виду. У объекта XDTO есть встроенный метод СоздатьОбъект(). Он автоматически определяет тип свойства, создает экземпляр этого типа и сразу записывает его в свойство родителя. Это избавляет нас от лишних переменных и ручного присваивания «снизу вверх».

Посмотрим, как упростится наш код:


// Создаем корень
ТипКорня = ФабрикаXDTO.Тип(ЛокальноеПространствоИмен, "insurer_id_t");
ОбъектКорня = ФабрикаXDTO.Создать(ТипКорня);

// Используем метод СоздатьОбъект для автоматического создания вложенных структур
ОбъектInsurerId = ОбъектКорня.СоздатьОбъект("InsurerId");
ОбъектCmbndId = ОбъектInsurerId.СоздатьОбъект("CmbndId");
ОбъектClrSysMmbId = ОбъектCmbndId.СоздатьОбъект("ClrSysMmbId");

// Заполняем конечное простое значение (атрибут или элемент с простым типом)
ОбъектClrSysMmbId.Id = "ТребуемоеЗначение";

Этот подход не только короче, но и производительнее, так как платформа оптимизирует работу с метаданными внутри метода СоздатьОбъект().

Способ 3: Автоматизация через рекурсивный обход

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

Рассмотрим пример функции, которая анализирует дерево типов пакета:


Функция ПолучитьСтруктуруТиповXDTO(ТекущийТип)
    СтруктураТипа = Новый Структура("ТипXDTO", ТекущийТип);
    
    Для каждого Свойство Из ТекущийТип.Свойства Цикл
        // Если форма свойства - элемент, и это сложный тип, идем вглубь
        Если Свойство.Форма = ФормаXML.Элемент Тогда
            Если Свойство.Тип.Вид = ВидТипаXDTO.Объект Тогда
                СтруктураТипа.Вставить(Свойство.Имя, ПолучитьСтруктуруТиповXDTO(Свойство.Тип));
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    Возврат СтруктураТипа;
КонецФункции

Такой подход полезен при построении универсальных интеграционных механизмов, где состав полей может меняться в зависимости от версии схемы.

Важные рекомендации при работе с XDTO

  1. Проверка на Неопределено: Перед обращением к свойствам вложенного объекта убедитесь, что он создан. В XDTO-объектах 1С вложенные свойства по умолчанию равны Неопределено, пока вы явно не создадите там объект.
  2. Минимальное количество элементов: Обратите внимание на свойство ВозможноПустое (или minOccurs в XSD). Если элемент обязателен, а вы его не создали (даже если он пустой), выгрузка в XML может не пройти валидацию.
  3. Использование Фабрики: Всегда помните, что типы в разных пакетах могут называться одинаково, но принадлежать разным пространствам имен (URI). Всегда указывайте правильный URI при обращении к ФабрикаXDTO.Тип().

Таким образом, работа с «Определениями типа» сводится к пониманию того, что эти типы не являются глобальными. Используя методы Свойства().Тип или СоздатьОбъект(), мы можем эффективно работать с любой глубиной вложенности XML-документа, сохраняя чистоту и читаемость кода.

← На главную