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

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

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

Выясним причину поведения платформы

Проанализируем структуру схемы XSD. В спецификации XML Schema корневой элемент (тег xs:element) может быть определен двумя способами:

  1. Через именованный тип: у тега xs:element задан атрибут type, который ссылается на отдельно объявленный xs:complexType с конкретным именем. В этом случае платформа 1С помещает тип в раздел «Типы объектов» пакета XDTO, и к нему можно напрямую обратиться через Фабрика.Тип(URIПространстваИмен, ИмяТипа).
  2. Через анонимный тип: описание полей и вложенных структур (тег xs:complexType) находится прямо внутри тега xs:element и не имеет собственного атрибута name.

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

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

Рассмотрим, как программно обойти ограничение анонимных типов, обратившись к свойствам пакета XDTO. Получить тип корневого узла можно непосредственно из коллекции КорневыеСвойства пакета, после чего фабрика сможет создать экземпляр объекта.

Посмотрим на пример работы со схемой, загруженной в метаданные конфигурации:


URIПространстваИмен = "http://v8.1c.ru/edi/edi_stnd/109";
ПакетXDTO = ФабрикаXDTO.Пакеты.Получить(URIПространстваИмен);

// Получаем корневое свойство пакета по имени или индексу
СвойствоКорневое = ПакетXDTO.КорневыеСвойства.Получить("СчетПК");
СчетПКТип = СвойствоКорневое.Тип;

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

// Заполняем реквизиты объекта
СчетПК.ДатаФормирования = Формат(ТекущаяДата(), "ДФ=yyyy-MM-dd");
СчетПК.НаименованиеОрганизации = "ООО ТД Комплексный";
СчетПК.ИНН = "7701234567";
СчетПК.РасчетныйСчетОрганизации = "40702810100000000001";
СчетПК.ИдПервичногоДокумента = Строка(Новый УникальныйИдентификатор);

// Выгружаем объект в XML-файл
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\output.xml", "windows-1251");
ЗаписьXML.ЗаписатьОбъявлениеXML();

// Важно передать локальное имя корневого элемента третьим параметром
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, СчетПК, "СчетПК");
ЗаписьXML.Закрыть();

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


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

// Заполняем поля вложенного объекта
ОбъектСотрудник.ФИО = "Иванов Иван Иванович";
ОбъектСотрудник.ТабельныйНомер = "00001";

// Если свойство множественное (список), добавляем через метод Добавить()
СчетПК.Сотрудники.Добавить(ОбъектСотрудник);

Способ 2. Создание фабрики XDTO «на лету» из файла XSD

В конфигурацию схему загружать необязательно. Разберем вариант, когда схема XSD хранится во внешнем файле. Мы создаем изолированную фабрику XDTO с помощью функции СоздатьФабрикуXDTO() и выполняем выгрузку данных.

Посмотрим на практический пример:


ПутьКСхемеXSD = "C:\temp\schema.xsd";
ПутьКВыходномуXML = "C:\temp\result.xml";

МассивСхем = Новый Массив;
МассивСхем.Добавить(ПутьКСхемеXSD);

// Создаем отдельную фабрику XDTO на основе переданных файлов XSD
Фабрика = СоздатьФабрикуXDTO(МассивСхем);

URIПространства = "http://v8.1c.ru/edi/edi_stnd/109";
Пакет = Фабрика.Пакеты.Получить(URIПространства);

// Извлекаем тип через коллекцию корневых свойств пакета
СвойствоДокумента = Пакет.КорневыеСвойства.Получить("СчетПК");
ДокументОбъект = Фабрика.Создать(СвойствоДокумента.Тип);

// Заполняем значения
ДокументОбъект.ДатаФормирования = Формат(ТекущаяДата(), "ДФ=yyyy-MM-dd");
ДокументОбъект.НаименованиеОрганизации = ОрганизацияНаименованиеПолное;
ДокументОбъект.ИНН = ОрганизацияИНН;
ДокументОбъект.РасчетныйСчетОрганизации = НомерСчета;
ДокументОбъект.ИдПервичногоДокумента = Строка(Док.УникальныйИдентификатор());

// Записываем сформированный документ в файл
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКВыходномуXML, "windows-1251");
ЗаписьXML.ЗаписатьОбъявлениеXML();

Фабрика.ЗаписатьXML(ЗаписьXML, ДокументОбъект, "СчетПК");
ЗаписьXML.Закрыть();

Важные нюансы при работе с анонимными структурами

Проанализируем технические особенности, на которые необходимо обратить внимание при формировании XML:

  1. Множественные элементы: если в XSD-схеме для элемента указано maxOccurs="unbounded" или число больше единицы, свойство в 1С инициализируется как СписокXDTO. Присваивать значение такому свойству через оператор равенства нельзя — возникнет ошибка времени выполнения. Заполнение выполняется строго через метод Добавить() соответствующего списка.
  2. Назначение типа при сериализации: в методе ФабрикаXDTO.ЗаписатьXML() параметр НазначениеТипаXML по умолчанию имеет значение, исключающее явную запись атрибута xsi:type. Для объектов с анонимными типами нельзя устанавливать параметр в значение НазначениеТипаXML.Явное, так как у типа нет имени, и выгруженный XML будет содержать некорректные атрибуты либо вызовет ошибку валидации.
  3. Именование тега при записи: если сериализуется объект, созданный на основе анонимного типа, в метод ЗаписатьXML() обязательно передавайте третий параметр — имя корневого элемента (например, "СчетПК"), чтобы платформа корректно сформировала открывающий и закрывающий теги.

Альтернативные решения

Если структура схемы находится под вашим контролем или есть готовые образцы выгрузки, рассмотрим еще два альтернативных варианта:

  1. Корректировка исходного файла XSD: можно вынести содержимое внутреннего тега xs:complexType за пределы xs:element, назначить ему явное имя (например, name="СчетПКТип") и сослаться на него из элемента через атрибут type="tns:СчетПКТип". После импорта в 1С данный тип сразу отобразится в ветке «Типы объектов», а код станет стандартным с обращением через Фабрика.Тип(...).
  2. Десериализация эталонного XML-документа: если имеется корректный пример XML-файла, можно прочитать его через метод ФабрикаXDTO.ПрочитатьXML(). Платформа самостоятельно воссоздаст дерево объектов с сохранением всех анонимных типов. После этого останется лишь изменить значения полей и сохранить объект обратно в XML-файл.
← На главную