При интеграции систем 1С со сторонними веб-сервисами и внешними базами данных разработчики регулярно сталкиваются с необходимостью импорта сложных XML-схем (XSD). К сожалению, файлы XSD от сторонних поставщиков часто содержат ошибки или не соответствуют строгим требованиям платформы «1С:Предприятие». Одной из наиболее распространенных проблем является отсутствие обязательного для 1С атрибута targetNamespace (целевого пространства имен) или некорректно заданные ограничения типов. Попытка загрузить такую схему напрямую в 1С приводит к ошибкам инициализации фабрики XDTO.
Править гигантские файлы вручную в текстовом редакторе — неблагодарное и ресурсозатратное занятие. В этой статье мы подробно разберем, как автоматизировать этот процесс программными средствами платформы 1С. Мы рассмотрим несколько эффективных подходов: от использования объектной модели DOM и XPath-запросов до мощных XSLT-преобразований и специализированных встроенных объектов работы со схемами.
Этот подход отлично подходит, когда нам нужно найти конкретные узлы в сложной структуре схемы и точечно скорректировать их. Объект ДокументDOM позволяет представить XML-файл в виде дерева, а встроенные механизмы XPath дают возможность моментально адресовать нужные элементы без необходимости ручного рекурсивного перебора всего файла.
Рассмотрим подробнее пример кода, в котором мы считываем XSD-схему, находим корневой тег schema с помощью XPath и принудительно устанавливаем недостающий атрибут targetNamespace, а также регистрируем префикс пространства имен:
// Инициализируем чтение XML-файла
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\schemas\source_schema.xsd");
// Загружаем схему в объектную модель DOM
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
ЧтениеXML.Закрыть();
// Создаем резолвер пространств имен для корректной работы XPath
РазыменовательПИ = Новый РазыменовательПространствИменDOM(ДокументDOM);
// XPath-выражение для поиска корневого элемента schema
ВыражениеXPath = "/*[local-name()='schema']";
РезультатXPath = ДокументDOM.ВычислитьВыражениеXPath(ВыражениеXPath, ДокументDOM, РазыменовательПИ, ТипРезультатаDOMXPath.ПервыйУпорядоченныйУзел);
Если РезультатXPath.ЕдинственныйУзелРезультата <> Неопределено Тогда
КорневойТег = РезультатXPath.ЕдинственныйУзелРезультата;
// Добавляем недостающее целевое пространство имен
КорневойТег.УстановитьАтрибут("targetNamespace", "http://www.example.com/new-namespace");
// Регистрируем префикс tns для этого же пространства имен
КорневойТег.УстановитьАтрибут("xmlns:tns", "http://www.example.com/new-namespace");
Сообщить("Целевое пространство имен успешно добавлено в корень схемы.");КонецЕсли;
// Записываем измененный документ обратно на диск
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\schemas\modified_schema.xsd", "UTF-8");
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
ЗаписьXML.Закрыть();
Данный метод показывает отличную точность на схемах любого уровня вложенности. Однако, если схема действительно огромна (десятки и сотни мегабайт), разбор XPath в памяти может потребовать значительного объема ресурсов. В таких ситуациях стоит рассмотреть более простые способы доступа к корню.
Если единственная проблема исходной схемы — отсутствие targetNamespace в корневом элементе, то использование XPath является избыточным. Мы можем получить доступ к корневому тегу схемы напрямую через свойство ЭлементДокумента объекта ДокументDOM. Это значительно быстрее и менее требовательно к памяти.
Проанализируем этот оптимизированный сценарий:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\schemas\source_schema.xsd");
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
ЧтениеXML.Закрыть();
// Прямой доступ к корневому элементу <xs:schema>
КорневойЭлемент = ДокументDOM.ЭлементДокумента;
// Проверяем, действительно ли это тег схемы
Если Найти(НРег(КорневойЭлемент.ИмяПолноты), "schema") > 0 Тогда
// Устанавливаем атрибуты напрямую
КорневойЭлемент.УстановитьАтрибут("targetNamespace", "http://www.example.com/my-namespace");
КорневойЭлемент.УстановитьАтрибут("xmlns:tns", "http://www.example.com/my-namespace");
Сообщить("Атрибуты успешно записаны напрямую в корень.");
КонецЕсли;
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\schemas\modified_schema.xsd", "UTF-8");
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
ЗаписьXML.Закрыть();
Этот способ работает в разы быстрее, так как платформе не требуется компилировать XPath-запрос и обходить дерево элементов.
Когда схема требует не просто добавления одного атрибута в корень, а масштабного перестроения (например, удаления неподдерживаемых ограничений типов, переименования тегов или изменения вложенности), идеальным инструментом становится ПреобразованиеXSL.
Этот механизм работает чрезвычайно быстро, так как выполняется на уровне оптимизированных системных C++ библиотек платформы. Разберем по шагам, как применить этот способ в 1С:
transform.xsl), который скопирует всю структуру схемы, но добавит в корень нужные атрибуты и трансформирует несовместимые узлы.Пример шаблона XSLT для добавления пространства имен в корневой элемент:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Шаблон по умолчанию: копирует все узлы и атрибуты как есть -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- Специальный шаблон для корневого элемента schema -->
<xsl:template match="xs:schema">
<xs:schema targetNamespace="http://www.example.com/modified" xmlns:tns="http://www.example.com/modified">
<!-- Копируем все дочерние атрибуты исходного тега, кроме старого targetNamespace (если он был) -->
<xsl:apply-templates select="@*[name()!='targetNamespace']"/>
<!-- Применяем шаблоны к внутреннему содержимому -->
<xsl:apply-templates select="node()"/>
</xs:schema>
</xsl:template>
</xsl:stylesheet>
Теперь напишем программный код в 1С для запуска этого XSLT-преобразования:
// Создаем объект преобразования XSL
Преобразование = Новый ПреобразованиеXSL;
// Загружаем наш xsl-шаблон из файла
Преобразование.ЗагрузитьИзФайла("C:\schemas\transform.xsl");
// Выполняем трансформацию исходного XSD-файла
РезультатСтрокой = Преобразование.ПреобразоватьИзФайла("C:\schemas\source_schema.xsd");
// Записываем полученную корректную схему в новый файл
ТекстовыйДокумент = Новый ТекстовыйЗапись;
ТекстовыйДокумент.Открыть("C:\schemas\modified_schema.xsd", КодировкаТекста.UTF8);
ТекстовыйДокумент.Записать(РезультатСтрокой);
ТекстовыйДокумент.Закрыть();
Сообщить("XSLT-преобразование успешно выполнено!");
Преимущество ПреобразованиеXSL заключается в том, что оно способно обрабатывать огромные XML-документы за доли секунды, тратя минимум процессорного времени 1С и исключая утечки памяти.
Платформа 1С предоставляет мощный встроенный инструмент — СхемаXML. С его помощью можно абстрагироваться от текстового или текстово-DOM представления XML и работать со структурой XSD как с набором типизированных объектов 1С.
Выясним, как загрузить схему в эту объектную модель и отредактировать ее свойства:
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\schemas\source_schema.xsd");
// Создаем набор схем и загружаем файл
НаборСхем = Новый НаборСхемXML;
НаборСхем.Добавить(ЧтениеXML);
ЧтениеXML.Закрыть();
// Извлекаем загруженную схему
Если НаборСхем.Количество() > 0 Тогда
Схема = НаборСхем.Получить(0);
// Мы можем программно анализировать ее директивы импорта, типы и элементы
Для Каждого Директива Из Схема.Директивы Цикл
Если ТипЗнч(Директива) = Тип("ИмпортXS") Тогда
// Здесь мы можем проанализировать или изменить импортируемые пространства имен
Сообщить("Схема импортирует пространство: " + Директива.ПространствоИмен);
КонецЕсли;
КонецЦикла;
// Также доступны коллекции элементов и типов
Для Каждого ОпределениеТипа Из Схема.Типы Цикл
Сообщить("Обнаружен тип данных: " + ОпределениеТипа.Имя);
КонецЦикла;
КонецЕсли;
Использование СхемаXML позволяет гарантировать, что все внесенные изменения будут строго соответствовать стандарту W3C XML Schema, исключая синтаксические ошибки ручного тегового редактирования.
Очень часто большие схемы разбиты на множество файлов, ссылающихся друг на друга. При импорте в 1С через НаборСхемXML разработчики регулярно сталкиваются с ошибкой: «Набор схем не может содержать схемы с одинаковыми целевыми пространствами имен». Это платформенное ограничение 1С при попытке загрузить несколько схем раздельно.
Чтобы решить эту проблему, нам нужно программно реализовать операцию «слияния» (merge) нескольких файлов в один монолитный XSD-файл:
ДокументDOM.<xs:include> и <xs:import>.schemaLocation) в другие экземпляры DOM.<xs:include> и <xs:import> из результирующего документа DOM, чтобы избежать конфликтов.Применяя данные подходы на практике, вы сможете полностью автоматизировать исправление даже самых сложных и некорректных XSD-схем, превращая часы рутинной ручной работы в мгновенно исполняемые и надежные алгоритмы.