Как убрать пространства имен (xmlns) из XML при использовании Фабрики XDTO

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

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

Суть проблемы и почему это происходит

Когда мы создаем объект XDTO на основании типа, определенного в пакете с указанным URI пространства имен, механизм 1С обязан пометить этот узел соответствующим идентификатором. Рассмотрим типовой код, который приводит к появлению лишних данных:


custXml = Новый ЗаписьXML;
custXml.УстановитьСтроку();
ТипCustomerDetail = ФабрикаXDTO.Тип("http://www.eee.ru/score", "typeCustomerDetail");
ОбъектCD = ФабрикаXDTO.Создать(ТипCustomerDetail);
ОбъектCD.lastName = "Иванов1";
ФабрикаXDTO.ЗаписатьXML(custXml, ОбъектCD, "customerDetails");
Результат = custXml.Закрыть();

На выходе мы получим узел, перегруженный служебной информацией. Если принимающая сторона ожидает простой тег customerDetails, нам необходимо вмешаться в процесс формирования файла. Рассмотрим основные методы решения задачи — от простых «костылей» до профессиональных инструментов.

Способ №1: Строковая замена (Post-processing)

Проанализируем самый быстрый и очевидный вариант — работу с результатом как с обычным текстом. Если XML небольшой, мы можем просто вырезать ненужные подстроки. Это решение часто критикуют за неэлегантность, но оно работает «здесь и сейчас».

Алгоритм действий:

  1. Сформировать XML в строку или во временный файл.
  2. Использовать функцию СтрЗаменить для удаления объявлений пространств имен.
  3. Передать очищенную строку далее по назначению.

// Получаем строку XML
ТекстXML = custXml.Закрыть();

// Удаляем конкретное пространство имен
ТекстXML = СтрЗаменить(ТекстXML, "xmlns=""http://www.eee.ru/score""", "");
ТекстXML = СтрЗаменить(ТекстXML, "xmlns:xs=""http://www.w3.org/2001/XMLSchema""", "");
ТекстXML = СтрЗаменить(ТекстXML, "xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""", "");

// Важно: могут остаться двойные пробелы или некорректно закрытые скобки тега
ТекстXML = СтрЗаменить(ТекстXML, "  >", ">");
ТекстXML = СтрЗаменить(ТекстXML, " >", ">");

Плюсы: Простота реализации. Минусы: Риск случайно заменить полезные данные внутри тегов, если они совпадают с URI пространства имен. Метод не подходит для очень больших файлов из-за ограничений памяти на работу со строками.

Способ №2: Потоковая фильтрация через Чтение/Запись XML

Выясним, как сделать очистку более надежной и производительной. Мы можем использовать последовательное чтение исходного «грязного» XML и запись его в новый объект ЗаписьXML, игнорируя данные о пространствах имен. Этот метод идеально подходит для больших файлов, так как данные обрабатываются порциями. При необходимости автоматизировать процесс редактирования структуры документа можно использовать внешнюю обработку для перезаписи и модификации XML-файлов.

Рассмотрим пример реализации функции очистки:


Функция ОчиститьXMLОтПространств(ИсходныйТекст)
    Чтение = Новый ЧтениеXML;
    Чтение.УстановитьСтроку(ИсходныйТекст);
    
    Запись = Новый ЗаписьXML;
    Запись.УстановитьСтроку();
    
    Пока Чтение.Прочитать() Цикл
        ТипУзла = Чтение.ТипУзла;
        
        Если ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
            // Записываем только локальное имя без URI
            Запись.ЗаписатьНачалоЭлемента(Чтение.ЛокальноеИмя);
            
            // Переносим атрибуты, если они не являются объявлениями xmlns
            Пока Чтение.ПрочитатьАтрибут() Цикл
                Если Чтение.Префикс <> "xmlns" И Чтение.ЛокальноеИмя <> "xmlns" Тогда
                    Запись.ЗаписатьАтрибут(Чтение.ЛокальноеИмя, Чтение.Значение);
                КонецЕсли;
            КонецЦикла;
            
        ИначеЕсли ТипУзла = ТипУзлаXML.Текст Тогда
            Запись.ЗаписатьТекст(Чтение.Значение);
            
        ИначеЕсли ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
            Запись.ЗаписатьКонецЭлемента();
        КонецЕсли;
    КонецЦикла;
    
    Возврат Запись.Закрыть();
КонецФункции

Этот подход гарантирует, что структура документа не будет нарушена, а все данные внутри тегов останутся в целости.

Способ №3: Использование XSLT-преобразования

Проанализируем наиболее «взрослый» и гибкий метод — применение XSL-шаблона. XSLT специально создан для трансформации XML-документов. Мы можем написать крошечный скрипт, который просто копирует элементы, отбрасывая пространства имен. Для расширения возможностей этой технологии можно использовать методику визуализации и преобразования данных через XSLT.

Разберем по шагам создание такого преобразования:

  1. Создаем текст XSL-шаблона, который выбирает все узлы и копирует их локальные имена.
  2. Загружаем этот текст в объект ПреобразованиеXSL.
  3. Выполняем трансформацию над исходным XML.

ТекстXSL = 
"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
|	<xsl:output method=""xml"" indent=""yes"" omit-xml-declaration=""yes""/>
|	<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;
Преобразование.ЗагрузитьИзСтроки(ТекстXSL);

// ИсходныйXML - это объект ЧтениеXML или строка
РезультатТрансформации = Преобразование.ПреобразоватьИзСтроки(ГрязныйXML);

Важный момент: Использование local-name() в шаблоне позволяет игнорировать префиксы и URI, создавая абсолютно «плоский» XML. Это самый надежный способ, если структура вложений очень сложная и включает десятки разных пакетов XDTO.

Способ №4: Программное создание XDTO-пакета без URI

Выясним, можно ли предотвратить появление xmlns еще на этапе генерации. В 1С ФабрикаXDTO ориентируется на метаданные пакета. Если в свойстве пакета «Пространство имен» (Target Namespace) указано значение, оно всегда будет попадать в XML.

Рассмотрим альтернативу:

  1. Вы можете создать в конфигурации свой пакет XDTO специально для обмена.
  2. Оставьте поле Пространство имен пустым.
  3. Опишите типы объектов внутри этого пакета.

При использовании такого пакета метод ФабрикаXDTO.ЗаписатьXML(Запись, Объект) увидит, что у объекта нет привязки к URI, и запишет «чистые» теги без атрибутов. Однако помните, что это потребует ручного перекладывания данных из ваших основных объектов в объекты этого «пустого» пакета.

Способ №5: Манипуляции через DOM

Если объем данных позволяет загрузить весь документ в память, можно воспользоваться объектной моделью DOM. Это позволяет точечно удалять атрибуты узлов.

Проанализируем пример кода:


Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(ГрязныйXML);
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(Чтение);

// Получаем корневой элемент
Корень = ДокументDOM.ЭлементДокумента;

// Удаляем атрибуты через итерацию по карте атрибутов
АтрибутыДляУдаления = Новый Массив;
Для Каждого Атрибут Из Корень.Атрибуты Цикл
    Если СтрНайти(Атрибут.Имя, "xmlns") > 0 Тогда
        АтрибутыДляУдаления.Добавить(Атрибут);
    КонецЕсли;
КонецЦикла;

Для Каждого Атр Из АтрибутыДляУдаления Цикл
    Корень.УдалитьАтрибутУзла(Атр);
КонецЦикла;

Стоит отметить, что DOM в 1С довольно требователен к ресурсам, поэтому для выгрузки реестров на 100 000 позиций лучше вернуться к Способу №2 (Потоковая фильтрация).

Резюме и рекомендации

Мы рассмотрели различные подходы к решению проблемы лишних пространств имен. Подведем итоги, чтобы выбрать оптимальный вариант:

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

← На главную