При работе со сложными схемами XML (XSD) разработчики 1С часто сталкиваются с необходимости вручную инициализировать каждый вложенный уровень и создавать типы через ФабрикаXDTO.Создать(). Если документ имеет глубокую структуру со множеством вложенных узлов, ручной код быстро разрастается до сотен строк. Рассмотрим, почему платформа 1С требует явного создания узлов и как можно автоматизировать этот процесс.
Выясним причину, почему платформа не может автоматически инициализировать сразу всё дерево документа при создании корневого элемента. Дело в том, что стандарт XSD (XML Schema Definition) содержит логические конструкции, которые нельзя однозначно интерпретировать без участия программиста:
minOccurs="0"): платформа не знает заранее, потребуется ли конкретный узел в выгружаемом файле.maxOccurs="unbounded"): заранее неизвестно количество элементов в массиве.xs:choice): схема допускает заполнение только одного из нескольких вариантов узлов.Тем не менее, постоянное прописывание типов для каждого уровня вручную можно свести к минимуму с помощью рекурсивных алгоритмов и работы с метаданными схемы.
Разберем универсальный подход, когда заполнение узлов происходит автоматически на основе пути к полю. Нам достаточно создать только корневой объект 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-строку или файл. Для этого используется объект ЗаписьXML и метод ЗаписатьXML() фабрики XDTO.
Рассмотрим стандартный пример записи объекта в XML-строку:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку("windows-1251");
ЗаписьXML.ЗаписатьОбъявлениеXML();
// КорневойРаздел — это наш полностью заполненный ОбъектXDTO
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, КорневойРаздел);
ТекстВыгрузки = ЗаписьXML.Закрыть();
Если задача заключается только в выгрузке данных без необходимости хранить и валидировать объект строго через XDTO-модель, можно рассмотреть альтернативные варианты:
ЗаписьXML: последовательный вывод узлов через методы ЗаписатьНачалоЭлемента(), ЗаписатьАтрибут() и ЗаписатьКонецЭлемента(). Этот способ работает быстрее всего и не потребляет лишнюю память на создание промежуточных объектов.СериализаторXDTO: если данные в 1С уже хранятся в виде структур, соответствий или прикладных объектов, их можно преобразовать в XDTO или XML в один шаг с помощью метода ЗаписатьXDTO() или ЗаписатьXML().ДокументDOM): позволяет собрать документ в памяти через методы СоздатьЭлемент() и записать его с помощью ЗаписьDOM.