Как программно отредактировать большую некорректную XSD-схему в 1С?

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

При интеграции систем 1С со сторонними веб-сервисами и внешними базами данных разработчики регулярно сталкиваются с необходимостью импорта сложных XML-схем (XSD). К сожалению, файлы XSD от сторонних поставщиков часто содержат ошибки или не соответствуют строгим требованиям платформы «1С:Предприятие». Одной из наиболее распространенных проблем является отсутствие обязательного для 1С атрибута targetNamespace (целевого пространства имен) или некорректно заданные ограничения типов. Попытка загрузить такую схему напрямую в 1С приводит к ошибкам инициализации фабрики XDTO.

Править гигантские файлы вручную в текстовом редакторе — неблагодарное и ресурсозатратное занятие. В этой статье мы подробно разберем, как автоматизировать этот процесс программными средствами платформы 1С. Мы рассмотрим несколько эффективных подходов: от использования объектной модели DOM и XPath-запросов до мощных XSLT-преобразований и специализированных встроенных объектов работы со схемами.

Решение 1: Использование объектной модели DOM и выражений XPath

Этот подход отлично подходит, когда нам нужно найти конкретные узлы в сложной структуре схемы и точечно скорректировать их. Объект Документ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 в памяти может потребовать значительного объема ресурсов. В таких ситуациях стоит рассмотреть более простые способы доступа к корню.

Решение 2: Прямая модификация корневых атрибутов DOM (без 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-запрос и обходить дерево элементов.

Решение 3: Преобразования XSLT для сложных структурных изменений

Когда схема требует не просто добавления одного атрибута в корень, а масштабного перестроения (например, удаления неподдерживаемых ограничений типов, переименования тегов или изменения вложенности), идеальным инструментом становится ПреобразованиеXSL.

Этот механизм работает чрезвычайно быстро, так как выполняется на уровне оптимизированных системных C++ библиотек платформы. Разберем по шагам, как применить этот способ в 1С:

  1. Шаг 1. Создаем файл шаблона XSLT (например, transform.xsl), который скопирует всю структуру схемы, но добавит в корень нужные атрибуты и трансформирует несовместимые узлы.
  2. Шаг 2. Загружаем шаблон в 1С и запускаем преобразование над исходным файлом схемы.

Пример шаблона 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С и исключая утечки памяти.

Решение 4: Программное манипулирование типизированными объектами Схемы XML

Платформа 1С предоставляет мощный встроенный инструмент — СхемаXML. С его помощью можно абстрагироваться от текстового или текстово-DOM представления XML и работать со структурой XSD как с набором типизированных объектов 1С.

Выясним, как загрузить схему в эту объектную модель и отредактировать ее свойства:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\schemas\source_schema.xsd");

// Создаем набор схем и загружаем файл
НаборСхем = Новый НаборСхемXML;
НаборСхем.Добавить(ЧтениеXML);
ЧтениеXML.Закрыть();

// Извлекаем загруженную схему
Если НаборСхем.Количество() > 0 Тогда
    Схема = НаборСхем.Получить(0);
    
    // Мы можем программно анализировать ее директивы импорта, типы и элементы
    Для Каждого Директива Из Схема.Директивы Цикл
        Если ТипЗнч(Директива) = Тип("ИмпортXS") Тогда
            // Здесь мы можем проанализировать или изменить импортируемые пространства имен
            Сообщить("Схема импортирует пространство: " + Директива.ПространствоИмен);
        КонецЕсли;
    КонецЦикла;
    
    // Также доступны коллекции элементов и типов
    Для Каждого ОпределениеТипа Из Схема.Типы Цикл
        Сообщить("Обнаружен тип данных: " + ОпределениеТипа.Имя);
    КонецЦикла;
КонецЕсли;

Использование СхемаXML позволяет гарантировать, что все внесенные изменения будут строго соответствовать стандарту W3C XML Schema, исключая синтаксические ошибки ручного тегового редактирования.

Решение 5: Решение проблемы слияния зависимых схем (Include/Import)

Очень часто большие схемы разбиты на множество файлов, ссылающихся друг на друга. При импорте в 1С через НаборСхемXML разработчики регулярно сталкиваются с ошибкой: «Набор схем не может содержать схемы с одинаковыми целевыми пространствами имен». Это платформенное ограничение 1С при попытке загрузить несколько схем раздельно.

Чтобы решить эту проблему, нам нужно программно реализовать операцию «слияния» (merge) нескольких файлов в один монолитный XSD-файл:

  1. Загрузите корневой XSD-файл в ДокументDOM.
  2. С помощью XPath найдите все теги <xs:include> и <xs:import>.
  3. Прочитайте содержимое указанных файлов (через schemaLocation) в другие экземпляры DOM.
  4. Перенесите все дочерние элементы (типы данных, объявления элементов) из импортированных схем в корневой элемент основной схемы.
  5. Удалите исходные теги <xs:include> и <xs:import> из результирующего документа DOM, чтобы избежать конфликтов.
  6. Сохраните монолитный файл и импортируйте его в 1С.

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

← На главную