Как сформировать XML без пространства имен по XSD-схеме с помощью ФабрикиXDTO в 1С?

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

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

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

Почему ФабрикаXDTO не работает со схемами без targetNamespace

Рассмотрим подробнее архитектурные особенности модели XDTO в 1С:Предприятии:

  1. Обязательность URI пространства имен: Любой пакет XDTO, создаваемый в дереве метаданных или загружаемый динамически в объект ФабрикаXDTO, должен иметь уникальный непустой URIПространстваИмен. Если схема XSD не содержит targetNamespace, платформа отбрасывает объявленные в ней типы.
  2. Невозможность создания безымянных типов: Метод ФабрикаXDTO.Создать() в качестве первого параметра обязательно принимает тип XDTO (ТипОбъектаXDTO или ТипЗначенияXDTO), получить который без указания пространства имен стандартным путем невозможно.
  3. Приемлемость по стандарту W3C: В спецификации XML Schema схемы без атрибута targetNamespace допустимы (их часто называют хамелеон-схемами), однако модель XDTO 1С не поддерживает генерацию XML-документов с полностью отсутствующими пространствами имен.

Способ 1. Формирование через XDTO с фиктивным пространством имен и текстовой постобработкой

Разберем по шагам наиболее быстрый и распространенный подход, который заключается в добавлении временного пространства имен в XSD-схему для комфортной сериализации объектов через ФабрикаXDTO, с последующим удалением лишних атрибутов xmlns из готового файла.

Шаг 1. Модификация схемы XSD: Добавляем в корневой элемент схемы фиктивный атрибут, например: targetNamespace="http://tempuri.org/export" и загружаем схему в конфигурацию как XDTO-пакет либо динамически через СоздатьФабрикуXDTO().

Шаг 2. Формирование XML-документа: Заполняем объект XDTO привычным способом и выгружаем его в файл с помощью объекта ЗаписьXML.

Шаг 3. Удаление объявлений пространств имен: Посмотрим на пример кода, выполняющего построчную замену с помощью объекта ТекстовыйДокумент:


ИмяФайлаXML = "C:\Exchange\export.xml";

// Запись сформированного XDTO-объекта в файл
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ИмяФайлаXML, "UTF-8");
ФабрикаXDTO.ЗаписатьXML(Запись, МойОбъектXDTO);
Запись.Закрыть();

// Очистка от объявления фиктивного пространства имен
Текст = Новый ТекстовыйДокумент;
Текст.Прочитать(ИмяФайлаXML, КодировкаТекста.UTF8);

Для Номер = 1 По Текст.КоличествоСтрок() Цикл
    СтрокаТекста = Текст.ПолучитьСтроку(Номер);
    СтрокаТекста = СтрЗаменить(СтрокаТекста, " xmlns=""http://tempuri.org/export""", "");
    СтрокаТекста = СтрЗаменить(СтрокаТекста, " xmlns:xs=""http://www.w3.org/2001/XMLSchema""", "");
    СтрокаТекста = СтрЗаменить(СтрокаТекста, " xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""", "");
    Текст.ЗаменитьСтроку(Номер, СтрокаТекста);
КонецЦикла;

Текст.Записать(ИмяФайлаXML, КодировкаТекста.UTF8);

Способ 2. Очистка XML с помощью регулярных выражений (начиная с платформы 8.3.23)

Начиная с версии платформы 1С 8.3.23, для строковых манипуляций доступны функции работы с регулярными выражениями. Это позволяет очистить любые объявления xmlns универсальным шаблоном без жесткой привязки к конкретной строке URI.

Посмотрим на пример реализации через чтение всего текста файла и замену по регулярному выражению:


// Считываем весь XML-файл в строковую переменную
ЧтениеТекста = Новый ЧтениеТекста(ИмяФайлаXML, КодировкаТекста.UTF8);
СодержимоеXML = ЧтениеТекста.Прочитать();
ЧтениеТекста.Закрыть();

// Удаляем все объявления пространств имен вида xmlns="..." и xmlns:префикс="..."
СодержимоеXML = СтрЗаменитьПоРегулярномуВыражению(СодержимоеXML, "\s+xmlns(:[a-zA-Z0-9_-]+)?=""[^""]*""", "");

// Перезаписываем итоговый файл
ЗаписьТекста = Новый ЗаписьТекста(ИмяФайлаXML, КодировкаТекста.UTF8);
ЗаписьТекста.Записать(СодержимоеXML);
ЗаписьТекста.Закрыть();

Важно: При использовании регулярных выражений или простой строковой замены убедитесь, что в самих выгружаемых строковых данных (например, в тексте комментариев или наименований) не встречаются сочетания символов, совпадающие с шаблоном xmlns="...", чтобы случайно не повредить полезные данные.

Способ 3. Безопасное удаление пространств имен через XSLT-преобразование

Если требуется гарантировать 100% синтаксическую корректность XML и исключить риски повреждения строковых данных в тегах, наиболее правильным решением является применение объекта ПреобразованиеXSL. XSLT-шаблон разбирает структуру XML как дерево и корректно переносит все теги и атрибуты без сохранения их пространств имен.

Разберем по шагам выполнение XSLT-трансформации:

  1. Формируем исходный XML-файл через ФабрикаXDTO с любым временным пространством имен.
  2. Применяем XSL-шаблон, который копирует имена элементов через функцию local-name(), исключая префиксы и атрибуты xmlns.

Посмотрим на пример кода 1С и структуру XSLT:


// Текст XSLT-преобразования для удаления пространств имен
ТекстXSLT = 
"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
|   <xsl:output method=""xml"" indent=""yes"" encoding=""UTF-8""/>
|   <xsl:template match=""*"">
|       <xsl:element name=""{local-name()}"">
|           <xsl:apply-templates select=""@* | node()""/>
|       </xsl:element>
|   </xsl:template>
|   <xsl:template match=""@*"">
|       <xsl:attribute name=""{local-name()}"">
|           <xsl:value-of select="".""/>
|       </xsl:attribute>
|   </xsl:template>
|</xsl:stylesheet>";

Преобразование = Новый ПреобразованиеXSL;
Преобразование.ЗагрузитьСтроку(ТекстXSLT);

// Выполняем трансформацию исходного файла в чистый результирующий файл
Преобразование.Преобразовать(ИмяИсходногоФайлаXML, ИмяЧистогоФайлаXML);

Способ 4. Формирование документа вручную через ЗаписьXML

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

Посмотрим на пример ручной записи:


Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл("C:\Exchange\direct_export.xml", "UTF-8");
Запись.ЗаписатьОбъявлениеXML();

// Запись корневого элемента без указания URI пространства имен
Запись.ЗаписатьНачалоЭлемента("RootDocument");

Запись.ЗаписатьНачалоЭлемента("Header");
Запись.ЗаписатьАтрибут("Number", "0000123");
Запись.ЗаписатьАтрибут("Date", Формат(ТекущаяДата(), "ДФ=yyyy-MM-dd"));
Запись.ЗаписатьКонецЭлемента(); // Header

Запись.ЗаписатьНачалоЭлемента("Items");
Запись.ЗаписатьНачалоЭлемента("Item");
Запись.ЗаписатьЭлемент("Code", "A-001");
Запись.ЗаписатьЭлемент("Quantity", "10");
Запись.ЗаписатьКонецЭлемента(); // Item
Запись.ЗаписатьКонецЭлемента(); // Items

Запись.ЗаписатьКонецЭлемента(); // RootDocument
Запись.Закрыть();

Как выполнить валидацию сформированного XML без пространств имен

Хотя ФабрикаXDTO не умеет работать со схемами без пространств имен, платформенный механизм проверки XML отлично с ними справляется. Объект СхемаXML умеет загружать исходную схему без targetNamespace, а объект ЧтениеXML позволяет валидировать итоговый очищенный файл.

Посмотрим на пример валидации:


Схема = Новый СхемаXML;
Схема.РасположениеСхемы = "C:\Schemas\original_schema.xsd";

ПараметрыЧтения = Новый ПараметрыЧтенияXML;
ПараметрыЧтения.Схемы.Добавить(Схема);
ПараметрыЧтения.ПроверятьДействительность = Истина;

Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл("C:\Exchange\export.xml", ПараметрыЧтения);

Попытка
    Пока Чтение.Прочитать() Цикл
        // Считываем весь файл до конца для полной проверки по схеме
    КонецЦикла;
    Сообщить("XML-документ успешно прошел валидацию!");
Исключение
    Сообщить("Ошибка валидации XML: " + ОписаниеОшибки(), СтатусСообщения.Важное);
КонецПопытки;

Чтение.Закрыть();

Итоги

При необходимости выгрузить XML без пространств имен по XSD-схеме оптимальным подходом является комбинирование инструментов:

  1. Для сложной структуры данных используем ФабрикаXDTO с добавлением фиктивного targetNamespace в схему, после чего очищаем файл с помощью ПреобразованиеXSL или строковой замены.
  2. Для валидации очищенного файла применяем объект СхемаXML вместе с ЧтениеXML, которые корректно работают с оригинальными схемами без пространств имен.
  3. Для простых плоских структур используем прямую запись через методы ЗаписьXML.
← На главную