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

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

При работе с планами обмена в 1С программисты часто сталкиваются с задачей передачи данных через сообщения обмена. Стандартный механизм формирования сообщения (использование объекта ЗаписьСообщенияСМС или работа с ПланыОбмена.СоздатьЗаписьСообщения) предполагает запись объектов в секцию Body. Если мы используем штатный метод ЗаписатьXML для ссылочных типов, 1С формирует структуру без лишних деклараций пространств имен внутри узла. Однако, при использовании ФабрикаXDTO, платформа стремится создать валидный с точки зрения стандартов XML фрагмент, добавляя атрибуты xmlns, xmlns:xs и xmlns:xsi. Это часто приводит к тому, что типовой механизм на стороне приемника не может корректно распознать и прочитать объект.

Рассмотрим подробнее, почему это происходит и как мы можем решить данную проблему несколькими способами.

Причина возникновения лишних атрибутов

Проанализируем ситуацию: ФабрикаXDTO работает строго на основании схем (XDTO-пакетов). Каждый тип в схеме привязан к определенному пространству имен (Namespace URI). Когда мы вызываем метод ЗаписатьXML, фабрика обязана указать, к какому пространству относится записываемый объект, чтобы его можно было однозначно идентифицировать при чтении. Если объект является корневым в текущем сеансе записи, фабрика добавляет декларации xmlns непосредственно в его тег.

В планах обмена секция v8msg:Body уже находится внутри пространства имен сообщения. Типовые механизмы чтения 1С (метод ПрочитатьXML) ожидают увидеть «чистые» теги объектов, тип которых определяется контекстом или метаданными, а не явными указаниями пространств имен в каждом узле. Выясним, как добиться такой «чистоты».

Способ 1. Использование Сериализатора XDTO

Вместо прямого обращения к ФабрикаXDTO, мы можем воспользоваться объектом СериализаторXDTO. Этот объект является высокоуровневой оберткой, которая умеет преобразовывать объекты метаданных 1С в формат XDTO и обратно, учитывая системные требования платформы. Зачастую использование сериализатора позволяет избежать избыточных деклараций, так как он понимает контекст системных пространств имен v8.

Посмотрим на пример кода, который подготавливает объект к записи:


// Подготовка данных
Номенклатура_Ссылка = Справочники.Номенклатура.НайтиПоКоду("000000001");
Номенклатура_Объект = Номенклатура_Ссылка.ПолучитьОбъект();

// Использование Сериализатора для записи в открытую ЗаписьXML
СериализаторXDTO.ЗаписатьXML(НоваяЗаписьXML, Номенклатура_Объект, НазначениеТипаXML.Явное);

Этот метод наиболее близок к стандартному поведению планов обмена, однако он работает только с объектами 1С. Если ваша задача — записать произвольный тип, описанный в вашем собственном XDTO-пакете, этот способ может не подойти.

Способ 2. Очистка XML через объектную модель документа (DOM)

Если нам принципиально нужно использовать ФабрикаXDTO для формирования сложной структуры, но мешают атрибуты xmlns, мы можем прибегнуть к программной очистке узла перед его окончательной записью в файл. Для этого воспользуемся возможностями DOM (Document Object Model). Разберем этот процесс по шагам:

  1. Запишем XDTO-объект во временный объект ЗаписьDOM.
  2. Получим дерево элементов.
  3. Обойдем узлы и удалим ненужные атрибуты декларации пространств имен.
  4. Запишем очищенный результат в основной поток сообщения обмена.

Проанализируем пример реализации такого подхода:


// 1. Создаем объект в памяти через Фабрику
Номенклатура_Тип = ФабрикаXDTO.Тип("http://v8.1c.ru/8.1/data/enterprise/current-config", "CatalogObject.Номенклатура");
Номенклатура_XDTO = ФабрикаXDTO.Создать(Номенклатура_Тип);
// ... заполнение свойств объекта ...

// 2. Записываем в DOM
ЗаписьDOM = Новый ЗаписьDOM;
ДокументDOM = Новый ДокументDOM;
ФабрикаXDTO.ЗаписатьXML(ЗаписьDOM, Номенклатура_XDTO, , , , ДокументDOM);

// 3. Находим корневой элемент и удаляем атрибуты xmlns
КорневойЭлемент = ДокументDOM.ЭлементДокумента;
СписокАтрибутовДляУдаления = Новый Массив;

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

Для Каждого ИмяАтрибута Из СписокАтрибутовДляУдаления Цикл
    КорневойЭлемент.УдалитьАтрибут(ИмяАтрибута);
КонецЦикла;

// 4. Записываем очищенный DOM в основной файл обмена
ЗаписатьDOM = Новый ЗаписьDOM;
ЗаписатьDOM.Записать(ДокументDOM, НоваяЗаписьXML);

Важный момент: использование DOM требует оперативной памяти для хранения всего дерева документа. Если выгружаемый объект очень велик, этот метод может замедлить работу системы. Однако для единичных объектов справочников или документов это самый надежный и «чистый» способ.

Способ 3. Текстовая замена в сформированном файле

Как упоминалось в обсуждении на форуме, одним из самых простых (хотя и менее «элегантных») способов является пост-обработка файла. Если мы точно знаем, какие строки вставляет фабрика, мы можем прочитать файл как текст и удалить лишние подстроки. Рассмотрим, как это можно реализовать после завершения формирования сообщения обмена.


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

// Удаляем декларации пространств имен, которые мешают приемнику
Содержимое = СтрЗаменить(Содержимое, "xmlns=""http://v8.1c.ru/8.1/data/enterprise/current-config""", "");
Содержимое = СтрЗаменить(Содержимое, "xmlns:xs=""http://www.w3.org/2001/XMLSchema""", "");
Содержимое = СтрЗаменить(Содержимое, "xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""", "");

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

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

Способ 4. Настройка свойств XDTO-пакета

Если вы создаете собственную схему обмена, обратите внимание на свойство Форма (Form) локальных элементов в XDTO-пакете. Если установить значение Unqualified (Не квалифицирован), то дочерние элементы объекта будут записываться без префиксов пространства имен. Это значительно упростит структуру XML. При переносе готовых структур в конфигурацию 1С можно использовать инструмент для конвертации схем XSD в модель XDTO.

Также, если пространство имен (URI) в самом XDTO-пакете оставить пустым, фабрика будет генерировать меньше служебной информации. Однако полностью избавиться от атрибута xmlns у корневого элемента при использовании метода ЗаписатьXML фабрики без дополнительных манипуляций (как в Способе 2) практически невозможно, так как это заложено в логику работы платформы с объектами XDTO.

Выводы и рекомендации

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

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

← На главную