Как убрать пространства имен из XML при выгрузке через пакет XDTO в 1С

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

При интеграции 1С с внешними информационными системами разработчики часто сталкиваются с жесткими требованиями к формату файлов обмена. Одно из наиболее распространенных требований — отсутствие каких-либо пространств имен в результирующем XML-документе. Внешний приемник ожидает чистые теги вроде <SWIFT_msg_fields>, но штатная сериализация 1С через фабрику XDTO принудительно генерирует тяжелые конструкции с атрибутами xmlns, xmlns:xsi и xmlns:xsd.

В этой статье мы подробно проанализируем, почему платформа ведет себя именно так, и разберем три практических способа избавиться от нежелательных пространств имен в зависимости от сложности вашей задачи.

Выясняем причину: почему XDTO принудительно добавляет пространства имен?

Архитектура XDTO (XML Data Transfer Objects) в платформе 1С:Предприятие концептуально неразрывно связана со стандартами консорциума W3C. Пакет XDTO всегда создается под определенное Целевое пространство имен (Target Namespace). Когда мы передаем объект XDTO в метод ФабрикаXDTO.ЗаписатьXML(), платформа обязана гарантировать валидность формируемого файла. Для этого она автоматически добавляет декларации пространств имен в корневой тег документа.

Попытки решить проблему «изнутри» фабрики, например, через передачу пустых параметров в метод ЗаписатьСоответствиеПространстваИмен() объекта ЗаписьXML, не дают нужного результата. Платформа либо проигнорирует эту настройку, либо перенесет пространства имен на уровень вложенных элементов, что сделает XML еще более перегруженным.

Поскольку внутри самого механизма XDTO нет волшебного «переключателя» для отключения пространств имен, нам придется использовать альтернативные подходы. Рассмотрим их по шагам.

Способ 1. Отказ от XDTO в пользу прямого формирования XML

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

Давайте посмотрим на практический пример реализации этого подхода:


ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("windows-1251", "1.0", Ложь);
ЗаписьXML.ОткрытьФайл("C:\ИмяФайла.xml", ПараметрыЗаписиXML);

// Записываем стандартный заголовок XML-документа
ЗаписьXML.ЗаписатьОбъявлениеXML();

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

// Заполняем вложенные данные
ЗаписьXML.ЗаписатьНачалоЭлемента("DocumentNumber");
ЗаписьXML.ЗаписатьТекст("12345");
ЗаписьXML.ЗаписатьКонецЭлемента();

ЗаписьXML.ЗаписатьНачалоЭлемента("Amount");
ЗаписьXML.ЗаписатьТекст("1500.50");
ЗаписьXML.ЗаписатьКонецЭлемента();

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

// Закрываем файл
ЗаписьXML.Закрыть();

Преимущества данного метода:

  1. Максимальное быстродействие: платформа не тратит ресурсы на создание тяжелой объектной структуры XDTO в памяти и ее валидацию.
  2. Полный контроль над структурой: вы получаете ровно те теги, которые указали в коде.

Недостатки метода:

  1. При сложной, многоуровневой иерархии данных ручное написание кода превращается в рутину, а сам код становится трудночитаемым и сложным в поддержке.

Способ 2. Применение XSLT-преобразования (Самый надежный способ)

Что делать, если иерархия данных слишком сложна, у вас уже спроектирован пакет XDTO и вы хотите продолжать использовать все удобства типизации объектов 1С? В этом случае идеальным решением будет постобработка сформированного XML-файла с помощью встроенного в 1С механизма XSLT-преобразования.

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

Рассмотрим пример реализации. Сначала подготовим специальный XSL-шаблон, который рекурсивно обходит дерево XML и перезаписывает элементы с их локальными именами (без префиксов и URI):


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@*|node()"/>
        </xsl:element>
    </xsl:template>
    <xsl:template match="@*|comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
</xsl:stylesheet>

Теперь напишем код в 1С, который применит это преобразование к выгружаемым данным:


// 1. Создаем XML-документ в памяти с помощью XDTO
ЗаписьВременная = Новый ЗаписьXML;
ЗаписьВременная.УстановитьСтроку();
ФабрикаXDTO.ЗаписатьXML(ЗаписьВременная, SWIFT_msg_fields);
ИсходныйТекстXML = ЗаписьВременная.Закрыть();

// 2. Описываем наш XSLT-шаблон очистки пространств имен
ТекстШаблонаXSLT = 
"<?xml version=""1.0"" encoding=""UTF-8""?>
|<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">
|   <xsl:template match=""*"">
|       <xsl:element name=""{local-name()}"">
|           <xsl:apply-templates select=""@*|node()""/>
|       </xsl:element>
|   </xsl:template>
|   <xsl:template match=""@*|comment()|processing-instruction()"">
|       <xsl:copy/>
|   </xsl:template>
|</xsl:stylesheet>";

// 3. Загружаем шаблон в процессор XSL
Преобразование = Новый ПреобразованиеXSL;
Преобразование.ЗагрузитьИзСтроки(ТекстШаблонаXSLT);

// 4. Подготавливаем чтение исходного XML и запись результирующего файла
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ИсходныйТекстXML);

ЗаписьИтоговая = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("windows-1251", "1.0", Ложь);
ЗаписьИтоговая.ОткрытьФайл("C:\ИтогБезПространствИмен.xml", ПараметрыЗаписи);

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

// Освобождаем ресурсы
ЧтениеXML.Закрыть();
ЗаписьИтоговая.Закрыть();

Преимущества данного метода:

  1. Абсолютная надежность: структура XML гарантированно не сломается, так как обработка идет на уровне парсера, а не текстовых строк.
  2. Вы сохраняете все преимущества разработки через фабрику XDTO.

Недостатки метода:

  1. При работе с файлами огромного размера (сотни мегабайт) преобразование XSLT может потребовать значительных объемов оперативной памяти.

Способ 3. Точечное строковое удаление (Высокопроизводительный метод БСП)

Если файлы выгрузки очень велики, а производительность критична, можно использовать метод постобработки текстового файла. Именно такой подход часто применяется в механизмах Библиотеки Стандартных Подсистем (БСП) 1С.

Важно помнить, что банальный вызов функции СтрЗаменить() для всего файла крайне опасен. Если строка, содержащая URI вашего пространства имен (например, "http://www.example.com/data"), случайно окажется внутри коммерческих данных (в наименовании товара или комментарии), она сотрется, нарушив целостность информации.

Поскольку платформа 1С всегда выводит объявления пространств имен строго в корневом теге, который гарантированно располагается на второй строке файла (сразу после объявления <?xml...?>), мы можем отредактировать только её. Давайте посмотрим, как это реализовать:


ПутьКФайлу = "C:\ИмяФайла.xml";

// Шаг 1. Формируем стандартный файл через XDTO
ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("windows-1251", "1.0", Ложь);
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, ПараметрыЗаписиXML);
ЗаписьXML.ЗаписатьОбъявлениеXML();
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, SWIFT_msg_fields);
ЗаписьXML.Закрыть();

// Шаг 2. Читаем файл как текстовый документ
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.Прочитать(ПутьКФайлу, КодировкаТекста.UTF8);

// Корневой тег гарантированно находится на 2-й строке документа
Если ТекстовыйДокумент.КоличествоСтрок() >= 2 Тогда
    СтрокаТега = ТекстовыйДокумент.ПолучитьСтроку(2);
    
    // Точечно удаляем атрибуты пространств имен из корневой строки
    СтрокаТега = СтрЗаменить(СтрокаТега, " xmlns=""НекоеПространствоИмен""", "");
    СтрокаТега = СтрЗаменить(СтрокаТега, " xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""", "");
    СтрокаТега = СтрЗаменить(СтрокаТега, " xmlns:xsd=""http://www.w3.org/2001/XMLSchema""", "");
    
    // Перезаписываем только целевую строку
    ТекстовыйДокумент.ЗаменитьСтроку(2, СтрокаТега);
    ТекстовыйДокумент.Записать(ПутьКФайлу, КодировкаТекста.UTF8);
КонецЕсли;

Преимущества данного метода:

  1. Высокая скорость обработки больших объемов данных за счет отсутствия сложного парсинга.
  2. Безопасность для полезных данных, так как мы обрабатываем только одну конкретную строку.

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

Мы подробно проанализировали три различных подхода к решению проблемы удаления пространств имен при выгрузке XML. Выбор конкретного метода зависит от структуры вашего проекта:

  1. Если структура простая — используйте прямую ручную запись (Способ 1). Это сэкономит время и ресурсы сервера.
  2. Если вы работаете со сложными иерархическими структурами данных среднего объема — используйте XSLT-трансформацию (Способ 2) как наиболее изящный и соответствующий стандартам XML способ.
  3. Если вам необходимо обрабатывать сверхбольшие объемы информации с сохранением преимуществ XDTO — оптимальным решением будет точечная строковая замена второй строки файла (Способ 3).
← На главную