Как правильно сформировать XML по схеме XSD с помощью Фабрики XDTO в 1С?

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

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

Анализ исходной структуры XML и ошибок проектирования схемы

Представим, что перед нами стоит задача сформировать следующий XML-документ:


<?xml version="1.0" encoding="utf-8"?>
<ROOT>
    <ArchivedLocalStocks>
        <ArchivedLocalStock WAREH_CODE="000000002" LOCALCODE="00000000100" LOT_ID="" DATE="2014-03-01T00:00:00" STOCK="438.000" DTLM="20140623 11:53" />
        <ArchivedLocalStock WAREH_CODE="000000002" LOCALCODE="00000000103" LOT_ID="" DATE="2014-03-01T00:00:00" STOCK="192.000" DTLM="20140623 11:53" />
    </ArchivedLocalStocks>
</ROOT>

Проанализируем типичные ошибки, которые допускаются при создании схемы для подобного документа:

  1. Использование анонимных типов для элементов коллекции. Если объявить тип элемента прямо внутри <xs:element name="ArchivedLocalStock"> без указания имени типа, фабрика 1С назначит ему системное составное имя. Получить такой тип через ФабрикаXDTO.Тип(...) в программном коде станет крайне неудобно.
  2. Объявление пустых типов. Попытка объявить <xs:complexType name="ROOT" /> и <xs:complexType name="ArchivedLocalStocks" /> полностью лишает фабрику информации о дочерних элементах.
  3. Лишние расширения типов. Конструкция <xs:extension base="xs:anyType"> не требуется, если элемент содержит только набор XML-атрибутов.
  4. Несоответствие форматов типов данных. Поле DATE имеет тип xs:dateTime, поэтому передавать в него произвольную текстовую строку нельзя — платформа 1С ожидает стандартное значение типа Дата. Поле DTLM содержит нестандартный формат "20140623 11:53", который не укладывается в спецификацию XML Schema для даты и времени, поэтому его необходимо объявлять строго как xs:string.

Выясняем причину ошибки свойства «Открытый»

В объектной модели XDTO каждый тип по умолчанию является закрытым (Открытый = Ложь). Это означает, что объекту разрешено содержать исключительно те дочерние теги и атрибуты, которые в явном виде задекларированы в схеме XSD.

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


xdtoArchivedLocalStoks.Добавить(ФормаXML.Элемент, "ArchivedStocks", "ArchivedLocalStock", xdtoArchivedLocalStok);

платформа 1С выдает ошибку, запрещая вставку не предусмотренных схемой свойств. Ручная установка признака Открытый = Истина в свойствах пакета XDTO снимает ограничение, но превращает строгую модель в неконтролируемый контейнер (аналог xs:any). Правильное решение состоит в том, чтобы корректно описать структуру вложенности в самой схеме XSD.

Проектирование корректной схемы XSD

Построим схему, в которой выделен корневой элемент, а вложенный тип строки вынесен в отдельный именованный тип данных:


<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="ArchivedStocks"
           xmlns:tns="ArchivedStocks"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">

    <!-- Описание атрибутов строки остатка -->
    <xs:complexType name="ArchivedLocalStock">
        <xs:attribute name="WAREH_CODE" type="xs:string" use="required" />
        <xs:attribute name="LOCALCODE" type="xs:string" use="required" />
        <xs:attribute name="LOT_ID" type="xs:string" />
        <xs:attribute name="DATE" type="xs:dateTime" use="required" />
        <xs:attribute name="STOCK" type="xs:decimal" use="required" />
        <xs:attribute name="DTLM" type="xs:string" />
    </xs:complexType>

    <!-- Описание списка строк -->
    <xs:complexType name="ArchivedLocalStocks">
        <xs:sequence>
            <xs:element name="ArchivedLocalStock" type="tns:ArchivedLocalStock" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>

    <!-- Описание корневого типа -->
    <xs:complexType name="ROOT">
        <xs:sequence>
            <xs:element name="ArchivedLocalStocks" type="tns:ArchivedLocalStocks" />
        </xs:sequence>
    </xs:complexType>

    <!-- Корневой элемент документа -->
    <xs:element name="ROOT" type="tns:ROOT" />

</xs:schema>

Формирование XML-документа в коде 1С

Рассмотрим подробнее программную работу с объектами и коллекциями XDTO. Когда элемент объявлен с атрибутом maxOccurs="unbounded", обращение к нему в коде возвращает коллекцию типа СписокXDTO. Метод Добавить() у такой коллекции принимает ровно один параметр — уже созданный и заполненный ОбъектXDTO.

Для одиночных вложенных элементов метод Добавить() вызывать не нужно: достаточно присвоить созданный дочерний объект соответствующему свойству родителя.

Разберем по шагам рабочий пример выгрузки:


// Задаем пространство имен согласно схеме
ПространствоИмен = "ArchivedStocks";

// Получаем типы XDTO из глобальной фабрики
ТипROOT = ФабрикаXDTO.Тип(ПространствоИмен, "ROOT");
ТипКоллекции = ФабрикаXDTO.Тип(ПространствоИмен, "ArchivedLocalStocks");
ТипСтроки = ФабрикаXDTO.Тип(ПространствоИмен, "ArchivedLocalStock");

// Создаем корневой объект и узел для списка
xdtoROOT = ФабрикаXDTO.Создать(ТипROOT);
xdtoArchivedLocalStocks = ФабрикаXDTO.Создать(ТипКоллекции);

// Заполняем строки остатков в цикле
Для Индекс = 1 По 3 Цикл
    xdtoСтрока = ФабрикаXDTO.Создать(ТипСтроки);
    xdtoСтрока.WAREH_CODE = "000000002";
    xdtoСтрока.LOCALCODE = "0000000010" + Строка(Индекс);
    xdtoСтрока.LOT_ID = "";
    
    // В поле типа xs:dateTime передаем стандартную Дату 1С
    xdtoСтрока.DATE = '20140301000000';
    xdtoСтрока.STOCK = 100 * Индекс;
    xdtoСтрока.DTLM = "20140623 11:53";
    
    // Добавляем созданный объект в коллекцию СписокXDTO
    xdtoArchivedLocalStocks.ArchivedLocalStock.Добавить(xdtoСтрока);
КонецЦикла;

// Привязываем заполненную коллекцию к корневому объекту
xdtoROOT.ArchivedLocalStocks = xdtoArchivedLocalStocks;

// Записываем сформированные данные в файл XML
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл("C:\ArchivedStocks.xml", "UTF-8");
Запись.ЗаписатьОбъявлениеXML();

// Метод сериализации запишет узел ROOT с учетом схемы пакета
ФабрикаXDTO.ЗаписатьXML(Запись, xdtoROOT);
Запись.Закрыть();

Практические рекомендации и ограничения

При реализации интеграций через XDTO полезно учитывать следующие нюансы платформы 1С:

  1. Динамическая загрузка схем. Если структура XML периодически меняется сторонней системой, схему не обязательно встраивать в конфигурацию как статический пакет XDTO. Можно использовать конструкцию СоздатьФабрикуXDTO(ПутьКФайлуСхемы), что позволит избежать постоянных доработок и обновлений конфигурации.
  2. Контроль потребления памяти. Построение дерева через ФабрикаXDTO создает модель данных полностью в оперативной памяти. Если требуется выгружать сотни тысяч строк, это может привести к ошибке нехватки памяти. В таких сценариях эффективнее использовать потоковую прямую запись через методы ЗаписьXML.ЗаписатьНачалоЭлемента(), ЗаписьXML.ЗаписатьАтрибут() и ЗаписьXML.ЗаписатьКонецЭлемента().
← На главную