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

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

При интеграции 1С со сторонними информационными системами часто возникает жесткое требование к структуре XML-документа: корневой элемент не должен содержать служебных атрибутов пространств имен. Однако при использовании механизма XDTO платформа 1С автоматически добавляет в корневой узел объявления схем.

Разберем подробнее, почему возникает данная особенность, и рассмотрим практические способы ее решения.

Почему Фабрика XDTO автоматически добавляет атрибуты пространств имен

Проанализируем архитектуру механизма XDTO в платформе 1С. Механизм строго ориентирован на спецификацию XML Schema (XSD). Любой пакет XDTO привязан к целевому пространству имен (Target Namespace). Когда мы вызываем метод ФабрикаXDTO.ЗаписатьXML(), платформа обязана гарантировать корректность сериализации типов данных.

В момент записи корневого тега сериализатор 1С принудительно генерирует следующие атрибуты:

  1. xmlns — целевое пространство имен схемы пакета;
  2. xmlns:xs="http://www.w3.org/2001/XMLSchema" — пространство имен стандартных типов XML Schema;
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" — пространство имен для передачи метаданных экземпляра (например, xsi:type или xsi:nil).

Важный момент: во встроенном языке 1С у объектов ФабрикаXDTO и ЗаписьXML нет стандартных параметров или флагов, позволяющих отключить генерацию этих атрибутов. Параметр НазначениеТипаXML.Неявное убирает типы у вложенных элементов, но не очищает сам корневой тег. Если принимающая сторона требует строго «чистый» тег вида <ROOT>, разработчику приходится обходить это ограничение платформы.

Способ 1. Построчная постобработка файла через ЗаписьТекста

Рассмотрим решение, предложенное автором темы. Оно заключается в формировании промежуточного файла через XDTO с последующей построчной перезаписью и заменой корневого тега.

Посмотрим на практическую реализацию этого метода:


Процедура ЗаписатьФайл(ИмяФайла, Данные)
    
    ПолноеИмяФайлаВывода     = ПолучитьПуть() + ИмяФайла + ".xml";
    ИмяПредварительногоФайла = ПолучитьПуть() + ИмяФайла + "._xml";
    
    // Проверяем соответствие структуры объекта XDTO схеме
    Данные.Проверить();
    
    // 1. Формируем первичный XML с помощью XDTO во временный файл
    Запись = Новый ЗаписьXML;
    Запись.ОткрытьФайл(ИмяПредварительногоФайла, "UTF-8");
    Запись.ЗаписатьОбъявлениеXML();
    
    Фабрика.ЗаписатьXML(Запись, Данные, "ROOT");
    Запись.Закрыть();
    
    // 2. Построчно читаем временный файл и заменяем открывающий тег ROOT
    ЗаписьТ = Новый ЗаписьТекста(ПолноеИмяФайлаВывода, КодировкаТекста.UTF8);
    ЧтениеТ = Новый ЧтениеТекста(ИмяПредварительногоФайла, КодировкаТекста.UTF8);
    
    СтрокаФайла = ЧтениеТ.ПрочитатьСтроку();
    Пока СтрокаФайла <> Неопределено Цикл 
        Если СокрЛ(Лев(СтрокаФайла, 5)) = "<ROOT" Тогда
            ЗаписьТ.ЗаписатьСтроку("<ROOT>");
        Иначе
            ЗаписьТ.ЗаписатьСтроку(СтрокаФайла);
        КонецЕсли;
        СтрокаФайла = ЧтениеТ.ПрочитатьСтроку();
    КонецЦикла;
    
    ЧтениеТ.Закрыть();
    ЗаписьТ.Закрыть();
    
    // 3. Удаляем временный файл
    Попытка
        УдалитьФайлы(ИмяПредварительногоФайла);
    Исключение
        // Обработка ошибки удаления временного файла
    КонецПопытки;
    
КонецПроцедуры

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

Способ 2. Оптимизированная строковая обработка в оперативной памяти

Выясним, как избежать создания временных файлов на диске. Объект ЗаписьXML умеет выгружать данные напрямую в строковую переменную через метод УстановитьСтроку(). Это ускоряет работу алгоритма и исключает проблемы с правами доступа к файловой системе.

Разберем по шагам алгоритм работы с памятью:


// Сериализуем XDTO в память
Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку("UTF-8");
Запись.ЗаписатьОбъявлениеXML();

ФабрикаXDTO.ЗаписатьXML(Запись, ДанныеXDTO, "ROOT");
СтрокаXML = Запись.Закрыть();

// Находим границы открывающего тега ROOT
ПозицияНачала = СтрНайти(СтрокаXML, "<ROOT");
Если ПозицияНачала > 0 Тогда
    ПозицияКонца = СтрНайти(СтрокаXML, ">",, ПозицияНачала);
    Если ПозицияКонца > 0 Тогда
        // Заменяем блок атрибутов тега ROOT на чистый тег
        СтрокаXML = Лев(СтрокаXML, ПозицияНачала - 1) + "<ROOT>" + Сред(СтрокаXML, ПозицияКонца + 1);
    КонецЕсли;
КонецЕсли;

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

Способ 3. Корректная очистка через объектную модель DOM

Если требуется строго следовать стандартам работы с XML и исключить манипуляции со строками, воспользуемся моделью DOM. Платформа 1С предоставляет для этого объекты ПостроительDOM, ДокументDOM и ЗаписьDOM.

Рассмотрим, как удалить атрибуты пространств имен программно через DOM:


// Считываем сформированный XML в объектную модель DOM
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайлаСАтрибутами);

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

// Получаем корневой элемент и удаляем нежелательные атрибуты
КорневойЭлемент = ДокументDOM.ЭлементДокумента;
Если КорневойЭлемент.ЕстьАтрибуты() Тогда
    // Удаляем стандартные пространства имен схемы
    КорневойЭлемент.УдалитьАтрибут("xmlns");
    КорневойЭлемент.УдалитьАтрибут("xmlns:xs");
    КорневойЭлемент.УдалитьАтрибут("xmlns:xsi");
КонецЕсли;

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

ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
ЗаписьXML.Закрыть();

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

Проанализируем альтернативный архитектурный подход: если формат выгрузки строго фиксирован и не требует сложной валидации по XSD-схеме, имеет смысл отказаться от пакета XDTO в пользу прямого использования ЗаписьXML.

При использовании методов ЗаписатьНачалоЭлемента(), ЗаписатьАтрибут() и ЗаписатьКонецЭлемента() платформа добавляет в результирующий XML исключительно те теги и атрибуты, которые вы указали явно в коде 1С, полностью исключая служебные пространства имен.

← На главную