При программном формировании XML-схем (XSD) средствами платформы 1С разработчики нередко сталкиваются с необходимостью снабдить генерируемые типы и элементы человекочитаемым описанием. По стандарту W3C XML Schema комментарии к структуре данных должны размещаться внутри конструкции <xs:annotation><xs:documentation>Текст описания</xs:documentation></xs:annotation>.
Однако при попытке использовать штатные объекты платформы АннотацияXS и ДокументацияXS текст комментария нередко попадает в атрибут source тега (свойство Источник), а не между открывающим и закрывающим тегами. Попробуем разобраться, почему объектная модель схемы ведет себя подобным образом и как правильно внедрить текстовое содержимое документации без потери структуры схемы.
Проанализируем состав свойств объекта ДокументацияXS в синтакс-помощнике платформы. Мы увидим только три свойства:
source.xml:lang.ЭлементDOM.У объекта принципиально отсутствуют свойства Значение или Текст. Согласно спецификации XML Schema, элемент xs:documentation объявлен со смешанным содержимым (mixed="true"). Он может содержать как неструктурированный текст, так и вложенные XML-элементы произвольных пространств имен. По этой причине платформа 1С не связывает тело тега с обычной строковой переменной, а полностью делегирует управление его наполнением объектной модели DOM.
Кроме того, если мы попытаемся импортировать файл XSD со встроенными аннотациями в дерево конфигурации как пакет XDTO, конфигуратор отсечет теги аннотаций. Пакеты XDTO в метаданных служат для сериализации и строгой типизации данных, поэтому любая служебная метаинформация при импорте игнорируется.
Рассмотрим две типичные ошибки, возникающие при попытке обойти это ограничение:
ДокументацияXS и сразу вызываем метод Документация.ОбновитьЭлементDOM(), а затем пытаемся обновить корень схемы через СхемаXML.ОбновитьЭлементDOM(), платформа аварийно завершает работу с системной ошибкой. Это происходит из-за рассинхронизации внутренней иерархии DOM: обновление DOM у дочернего оторванного узла до построения общего дерева схемы разрушает указатели на родительские структуры.СхемаXML есть свойство СхемаДляСхемыXML, позволяющее получить метаописание схемы через XDTO. Однако при попытке создать объект схемы через фабрику XDTO и добавить текст в последовательность (Последовательность.Добавить("текст")) возникает исключительная ситуация. Ограничение механизмов XDTO запрещает добавлять строки в последовательности типов, для которых явно не установлен признак Смешанный = Истина, а в анонимных типах встроенной схемы W3C этот признак не проинициализирован должным образом.Разберем по шагам наиболее стабильный и поддерживаемый вариант. Сначала мы выстраиваем всю иерархию типов и элементов через объекты модели Схема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.Закрыть();
Рассмотрим подробнее ключевые моменты этого кода:
ОбновитьЭлементDOM() у промежуточных объектов (ТипСоставной, Аннотация, Документация). Мы вызываем его исключительно у переменной Схема.Схема.ОбновитьЭлементDOM() свойство Документация.ЭлементDOM автоматически связывается с узлом <xs:documentation>, расположенным внутри сформированного дерева Схема.ДокументDOM.Документация.ТекстовоеСодержимое создает внутри тега текстовый DOM-узел с переданной строкой без нарушения целостности XML. Альтернативно можно использовать метод Схема.Документ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.