Как упростить создание и заполнение объектов XDTO для выгрузки в XML в 1С?

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

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

Почему 1С не создает все вложенные узлы XDTO автоматически?

Выясним причину, почему платформа не может автоматически инициализировать сразу всё дерево документа при создании корневого элемента. Дело в том, что стандарт XSD (XML Schema Definition) содержит логические конструкции, которые нельзя однозначно интерпретировать без участия программиста:

  1. Необязательные элементы (minOccurs="0"): платформа не знает заранее, потребуется ли конкретный узел в выгружаемом файле.
  2. Коллекции и списки (maxOccurs="unbounded"): заранее неизвестно количество элементов в массиве.
  3. Конструкции выбора (xs:choice): схема допускает заполнение только одного из нескольких вариантов узлов.
  4. Абстрактные и составные типы: при создании конкретного элемента требуется явно указывать производный тип.

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

Рекурсивное заполнение структуры XDTO по путям свойств

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

Для реализации подготавливается объект Соответствие, где ключом выступает составной путь к полю (например, "specifiedPerson/fio"), а значением — передаваемые данные.

Посмотрим на пример вызова и саму рекурсивную процедуру:


// Создаем только корневой объект XDTO
VetDocumentStatusChangeDO = ФабрикаXD.Создать("http://api.vetrf.ru/schema/cdm/mercury/vet-document/v2", "VetDocumentStatusChange");

// Задаем пути к свойствам и их значения
VetDocumentStatusChangePM = Новый Соответствие;
VetDocumentStatusChangePM.Вставить("specifiedPerson/fio", confirmedBy_fio);
VetDocumentStatusChangePM.Вставить("specifiedPerson/post", confirmedBy_post);
VetDocumentStatusChangePM.Вставить("status", "CONFIRMED");

// Запускаем автоматическое заполнение
ЗаполнитьСвойстваОбъектаXDTOрек(VetDocumentStatusChangeDO, VetDocumentStatusChangePM);

Проанализируем работу самой процедуры ЗаполнитьСвойстваОбъектаXDTOрек. Она разбирает ключ пути, проверяет существование промежуточного узла и при его отсутствии создает необходимый ОбъектXDTO, используя метаданные типа текущего объекта:


Процедура ЗаполнитьСвойстваОбъектаXDTOрек(ОбъектXDTO, тСоответствие)
    Для Каждого Эл Из тСоответствие Цикл
        ПозицияСлеша = Найти(Эл.Ключ, "/");
        Если ПозицияСлеша = 0 Тогда
            ЛевоеИмяПоля = Эл.Ключ;
            ПравыеИменаПолей = Эл.Ключ;
        Иначе
            ЛевоеИмяПоля = Лев(Эл.Ключ, ПозицияСлеша - 1);
            ПравыеИменаПолей = Прав(Эл.Ключ, СтрДлина(Эл.Ключ) - ПозицияСлеша);
        КонецЕсли;

        Если ЛевоеИмяПоля = ПравыеИменаПолей Тогда
            // Достигли конечного свойства
            Если ТипЗнч(ОбъектXDTO[ЛевоеИмяПоля]) = Тип("СписокXDTO") Тогда
                ОбъектXDTO[ЛевоеИмяПоля].Добавить(Эл.Значение);
            Иначе
                ОбъектXDTO[ЛевоеИмяПоля] = Эл.Значение;
            КонецЕсли;
        Иначе
            // Если промежуточный объект еще не создан — создаем его динамически
            Если ОбъектXDTO[ЛевоеИмяПоля] = Неопределено Тогда
                СвойствоXDTO = ОбъектXDTO.Тип().Свойства.Получить(ЛевоеИмяПоля);
                ОбъектXDTO[ЛевоеИмяПоля] = ФабрикаXD.Создать(СвойствоXDTO.Тип.URIПространстваИмен, СвойствоXDTO.Тип.Имя);
            КонецЕсли;

            ИменаПолей = Новый Соответствие;
            ИменаПолей.Вставить(ПравыеИменаПолей, Эл.Значение);
            
            // Рекурсивный вызов для следующего уровня вложенности
            ЗаполнитьСвойстваОбъектаXDTOрек(ОбъектXDTO[ЛевоеИмяПоля], ИменаПолей);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Сериализация готового объекта XDTO в XML

После того как структура XDTO сформирована и заполнена данными, её необходимо выгрузить в итоговую XML-строку или файл. Для этого используется объект ЗаписьXML и метод ЗаписатьXML() фабрики XDTO.

Рассмотрим стандартный пример записи объекта в XML-строку:


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("windows-1251");
ЗаписьXML.ЗаписатьОбъявлениеXML();

// КорневойРаздел — это наш полностью заполненный ОбъектXDTO
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, КорневойРаздел);

ТекстВыгрузки = ЗаписьXML.Закрыть();

Альтернативные способы формирования XML в 1С

Если задача заключается только в выгрузке данных без необходимости хранить и валидировать объект строго через XDTO-модель, можно рассмотреть альтернативные варианты:

  1. Прямая запись через ЗаписьXML: последовательный вывод узлов через методы ЗаписатьНачалоЭлемента(), ЗаписатьАтрибут() и ЗаписатьКонецЭлемента(). Этот способ работает быстрее всего и не потребляет лишнюю память на создание промежуточных объектов.
  2. Использование СериализаторXDTO: если данные в 1С уже хранятся в виде структур, соответствий или прикладных объектов, их можно преобразовать в XDTO или XML в один шаг с помощью метода ЗаписатьXDTO() или ЗаписатьXML().
  3. Объектная модель DOM (ДокументDOM): позволяет собрать документ в памяти через методы СоздатьЭлемент() и записать его с помощью ЗаписьDOM.
← На главную