Как добавить текст внутрь тега xs:documentation при программном формировании XSD-схемы в 1С?

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

При программном формировании XML-схем (XSD) средствами платформы 1С разработчики нередко сталкиваются с необходимостью снабдить генерируемые типы и элементы человекочитаемым описанием. По стандарту W3C XML Schema комментарии к структуре данных должны размещаться внутри конструкции <xs:annotation><xs:documentation>Текст описания</xs:documentation></xs:annotation>.

Однако при попытке использовать штатные объекты платформы АннотацияXS и ДокументацияXS текст комментария нередко попадает в атрибут source тега (свойство Источник), а не между открывающим и закрывающим тегами. Попробуем разобраться, почему объектная модель схемы ведет себя подобным образом и как правильно внедрить текстовое содержимое документации без потери структуры схемы.

В чем заключается архитектурная проблема

Проанализируем состав свойств объекта ДокументацияXS в синтакс-помощнике платформы. Мы увидим только три свойства:

  1. Источник — строковое свойство, транслирующееся в XML-атрибут source.
  2. Язык — строковое свойство, транслирующееся в XML-атрибут xml:lang.
  3. ЭлементDOM — ссылка на объект модели документа ЭлементDOM.

У объекта принципиально отсутствуют свойства Значение или Текст. Согласно спецификации XML Schema, элемент xs:documentation объявлен со смешанным содержимым (mixed="true"). Он может содержать как неструктурированный текст, так и вложенные XML-элементы произвольных пространств имен. По этой причине платформа 1С не связывает тело тега с обычной строковой переменной, а полностью делегирует управление его наполнением объектной модели DOM.

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

Ошибки при обновлении DOM и работа с фабрикой XDTO

Рассмотрим две типичные ошибки, возникающие при попытке обойти это ограничение:

  1. Вызов ОбновитьЭлементDOM() у дочернего объекта. Если мы создаем объект ДокументацияXS и сразу вызываем метод Документация.ОбновитьЭлементDOM(), а затем пытаемся обновить корень схемы через СхемаXML.ОбновитьЭлементDOM(), платформа аварийно завершает работу с системной ошибкой. Это происходит из-за рассинхронизации внутренней иерархии DOM: обновление DOM у дочернего оторванного узла до построения общего дерева схемы разрушает указатели на родительские структуры.
  2. Использование ФабрикаXDTO и СхемаДляСхемыXML. У объекта СхемаXML есть свойство СхемаДляСхемыXML, позволяющее получить метаописание схемы через XDTO. Однако при попытке создать объект схемы через фабрику XDTO и добавить текст в последовательность (Последовательность.Добавить("текст")) возникает исключительная ситуация. Ограничение механизмов XDTO запрещает добавлять строки в последовательности типов, для которых явно не установлен признак Смешанный = Истина, а в анонимных типах встроенной схемы W3C этот признак не проинициализирован должным образом.

Корректное решение: совместное использование СхемаXML и модели DOM

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

Посмотрим на практический пример программного создания схемы с текстовой аннотацией:


// 1. Создаем корневую схему XML
Схема = Новый СхемаXML;
Схема.ЦелевоеПространствоИмен = "http://example.com/schema";

// 2. Создаем составной тип
ТипСоставной = Новый ОпределениеСоставногоТипаXS;
ТипСоставной.Имя = "КонтрагентТип";

Часть = Новый ГруппаМоделиXS;
Фрагмент = Новый ФрагментXS;
Фрагмент.Часть = Часть;
ТипСоставной.Содержимое = Фрагмент;

// 3. Создаем аннотацию и документацию
Аннотация = Новый АннотацияXS;
Документация = Новый ДокументацияXS;
Аннотация.Состав.Добавить(Документация);

// Привязываем аннотацию к созданному типу
ТипСоставной.Аннотация = Аннотация;

// Добавляем тип в коллекцию схемы
Схема.ОпределенияТипов.Добавить(ТипСоставной);

// 4. Синхронизируем DOM-дерево схемы строго один раз на уровне корня
Схема.ОбновитьЭлементDOM();

// 5. Заполняем текстовое содержимое тега через полученный ЭлементDOM
// Свойство ЭлементDOM у объекта Документация теперь указывает на актуальный узел схемы
УзелДокументации = Документация.ЭлементDOM;
Если УзелДокументации <> Неопределено Тогда
    УзелДокументации.ТекстовоеСодержимое = "Описание типа данных: основные реквизиты контрагента";
КонецЕсли;

// 6. Выгружаем сформированную схему в XML-файл или строку
ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ЗаписьXML.УстановитьСтроку(ПараметрыЗаписи);

ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(Схема.ДокументDOM, ЗаписьXML);

ИтоговыйXML = ЗаписьXML.Закрыть();

Рассмотрим подробнее ключевые моменты этого кода:

  1. Мы не вызываем метод ОбновитьЭлементDOM() у промежуточных объектов (ТипСоставной, Аннотация, Документация). Мы вызываем его исключительно у переменной Схема.
  2. После вызова метода Схема.ОбновитьЭлементDOM() свойство Документация.ЭлементDOM автоматически связывается с узлом <xs:documentation>, расположенным внутри сформированного дерева Схема.ДокументDOM.
  3. Нам не требуется выполнять поиск по дереву через XPath или обходить дочерние узлы: ссылка на DOM-элемент уже доступна напрямую из объекта Документация.
  4. Присвоение значения свойству ТекстовоеСодержимое создает внутри тега текстовый DOM-узел с переданной строкой без нарушения целостности XML. Альтернативно можно использовать метод Схема.ДокументDOM.СоздатьТекстовыйУзел() и добавить его через ДобавитьДочерний().

Альтернативный вариант: формирование схемы напрямую через DOM

Если генерация схемы требует нетиповых элементов XSD, множественных комментариев или неструктурированных вставок appinfo, можно полностью отказаться от использования компонентов СхемаXML в пользу генерации дерева через ДокументDOM или потоковой записи с помощью ЗаписьXML.

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


ПространствоСхемы = "http://www.w3.org/2001/XMLSchema";

// Инициализируем документ DOM с корневым элементом schema
ДокументDOM = Новый ДокументDOM;
КореньСхемы = ДокументDOM.СоздатьЭлементNS(ПространствоСхемы, "xs:schema");
ДокументDOM.ДобавитьДочерний(КореньСхемы);

// Создаем объявление составного типа
УзелТипа = ДокументDOM.СоздатьЭлементNS(ПространствоСхемы, "xs:complexType");
УзелТипа.УстановитьАтрибут("name", "КонтрагентТип");
КореньСхемы.ДобавитьДочерний(УзелТипа);

// Создаем блок аннотации и документации
УзелАннотации = ДокументDOM.СоздатьЭлементNS(ПространствоСхемы, "xs:annotation");
УзелДокументации = ДокументDOM.СоздатьЭлементNS(ПространствоСхемы, "xs:documentation");

// Создаем текстовый узел и помещаем его внутрь документации
ТекстовыйУзел = ДокументDOM.СоздатьТекстовыйУзел("Описание контрагента");
УзелДокументации.ДобавитьДочерний(ТекстовыйУзел);

УзелАннотации.ДобавитьДочерний(УзелДокументации);
УзелТипа.ДобавитьДочерний(УзелАннотации);

// Сохраняем результат
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();

ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);

РезультатXML = ЗаписьXML.Закрыть();

Генерация через DOM или ЗаписьXML требует более детального описания каждого тега вручную, однако дает полный контроль над результирующим документом, исключая проблемы с типами и ограничения встроенных в платформу объектов модели схем XML.

← На главную