При интеграции с внешними системами и разборе сложных форматов регламентированной отчетности разработчики часто используют механизм XDTO. Создав объект ФабрикаXDTO на основании XSD-схем, можно легко сериализовать и десериализовать XML-документы. Однако при попытке программно исследовать типы фабрики разработчики сталкиваются с проблемой: в объектах ТипОбъектаXDTO и СвойствоXDTO отсутствуют пользовательские описания (теги xs:documentation, xs:annotation, атрибуты Description), а вложенные структуры xs:sequence преобразуются в плоский список свойств.
Разберем причины такого поведения платформы 1С и пошагово реализуем способы извлечения полной структуры и описаний схемы.
Проанализируем назначение механизма XDTO в платформе 1С:Предприятие:
xs:annotation, xs:documentation, xs:appinfo) и комментарии отсекаются платформой. Они не сохраняются в объектах ПакетXDTO или ТипОбъектаXDTO.xs:sequence, xs:choice, xs:all) при импорте в фабрику разворачиваются в единый плоский список свойств объекта с сохранением порядка и количественных ограничений (МинимальноеКоличество, МаксимальноеКоличество), но теряют информацию о вложенных секциях.Таким образом, если перед нами стоит задача не просто передавать данные, но и генерировать интерфейс, строить документацию или выводить подсказки для пользователей на основе XSD, стандартной ФабрикиXDTO недостаточно.
Так как файл XSD представляет собой стандартный XML-документ, для чтения комментариев и блоков xs:documentation используем объектную модель ДокументDOM и объект ПостроительDOM. Это позволяет получить полное дерево схемы со всеми комментариями и аннотациями.
Рассмотрим пример кода для загрузки схемы в DOM и извлечения документации комплексных типов:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлуXSD);
Построитель = Новый ПостроительDOM;
ДокументСхемы = Построитель.Прочитать(Чтение);
Чтение.Закрыть();
// Обойдем все дочерние узлы корневого элемента схемы
КорневойЭлемент = ДокументСхемы.ЭлементДокумента;
Для Каждого Узел Из КорневойЭлемент.ДочерниеУзлы Цикл
Если Узел.ТипУзла = ТипУзлаDOM.Элемент И Узел.ЛокальноеИмя = "complexType" Тогда
ИмяТипа = Узел.ПолучитьАтрибут("name");
// Ищем вложенный узел аннотации (xs:annotation -> xs:documentation)
ОписаниеТипа = "";
Для Каждого Дочерний Из Узел.ДочерниеУзлы Цикл
Если Дочерний.ТипУзла = ТипУзлаDOM.Элемент И Дочерний.ЛокальноеИмя = "annotation" Тогда
Для Каждого УзелАннотации Из Дочерний.ДочерниеУзлы Цикл
Если УзелАннотации.ТипУзла = ТипУзлаDOM.Элемент И УзелАннотации.ЛокальноеИмя = "documentation" Тогда
ОписаниеТипа = СокрЛП(УзелАннотации.ТекстовоеСодержимое);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Сообщить(СтрШаблон("Тип: %1 | Описание: %2", ИмяТипа, ОписаниеТипа));
КонецЕсли;
КонецЦикла;
Наиболее удобная архитектурная практика при работе со сложными схемами — объединить возможности валидации через XDTO и метаданные из DOM:
СоздатьФабрикуXDTO() для работы со структурой типов и значениями.ПостроительDOM и строим справочную таблицу или Соответствие, где ключом является составное имя вида "URIПространстваИмен#ИмяТипа.ИмяСвойства", а значением — текст описания.Разберем пример реализации карты описаний:
Функция ПолучитьКартуОписанийСхемы(ПутьКФайлуXSD)
Карта = Новый Соответствие;
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлуXSD);
Построитель = Новый ПостроительDOM;
Документ = Построитель.Прочитать(Чтение);
Чтение.Закрыть();
// Получаем все элементы documentation в документе
СписокДокументаций = Документ.ПолучитьЭлементыПоИмени("xs:documentation");
Если СписокДокументаций.Количество() = 0 Тогда
СписокДокументаций = Документ.ПолучитьЭлементыПоИмени("documentation");
КонецЕсли;
Для Индекс = 0 По СписокДокументаций.Количество() - 1 Цикл
ЭлементDoc = СписокДокументаций.Получить(Индекс);
Родитель = ЭлементDoc.РодительскийУзел; // xs:annotation
Если Родитель <> Неопределено И Родитель.РодительскийУзел <> Неопределено Тогда
ЦелевойЭлемент = Родитель.РодительскийУзел; // complexType или element
ИмяЦели = ЦелевойЭлемент.ПолучитьАтрибут("name");
Если ЗначениеЗаполнено(ИмяЦели) Тогда
Карта.Вставить(ИмяЦели, СокрЛП(ЭлементDoc.ТекстовоеСодержимое));
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Карта;
КонецФункции
Если файл схемы имеет большой размер (десятки мегабайт), создание полного дерева DOM может вызвать повышенное потребление оперативной памяти. В этом случае эффективнее применить объект ЧтениеXML в потоковом режиме.
Посмотрим на пример потокового поиска описаний:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлуXSD);
ТекущийТип = "";
ВнутриАннотации = Ложь;
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
Если Чтение.ЛокальноеИмя = "complexType" Или Чтение.ЛокальноеИмя = "element" Тогда
ТекущийТип = Чтение.ПолучитьАтрибут("name");
ИначеЕсли Чтение.ЛокальноеИмя = "annotation" Тогда
ВнутриАннотации = Истина;
ИначеЕсли Чтение.ЛокальноеИмя = "documentation" И ВнутриАннотации Тогда
ТекстОписания = Чтение.ПрочитатьТекст();
Если ЗначениеЗаполнено(ТекущийТип) Тогда
Сообщить(СтрШаблон("Элемент: %1 -> Описание: %2", ТекущийТип, ТекстОписания));
КонецЕсли;
КонецЕсли;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
Если Чтение.ЛокальноеИмя = "annotation" Тогда
ВнутриАннотации = Ложь;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Чтение.Закрыть();
Если требуется различать вложенные xs:sequence, xs:choice и группы элементов, которые теряются в фабрике XDTO, можно использовать специализированный объект СхемаXML:
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлуXSD);
ПостроительСхем = Новый ПостроительСхемXML;
Схема = ПостроительСхем.СоздатьСхемуXML(Чтение);
Чтение.Закрыть();
// Объект СхемаXML содержит коллекцию Элементы, Типы, Группы
Для Каждого ЭлементСхемы Из Схема.Элементы Цикл
// Доступ к модели частиц и композиторов XSD
Сообщить(СтрШаблон("Имя элемента схемы: %1", ЭлементСхемы.Имя));
КонецЦикла;
Итог: ФабрикаXDTO не предназначена для извлечения описаний и рефлексивного анализа метаданных схемы. Для решения задач выгрузки документации, подсказок или нестандартной структуры используйте ПостроительDOM или потоковое ЧтениеXML параллельно с фабрикой.