При интеграции 1С с внешними системами через протоколы обмена данными (например, SOAP или REST) программисты часто сталкиваются с особенностью работы объекта ЗаписьXML. Платформа 1С при указании пространства имен автоматически генерирует префиксы вида d3p1, d3p2 и так далее. Несмотря на то что с точки зрения стандартов XML наличие префикса не является ошибкой (если он корректно сопоставлен с URI), многие принимающие системы или упрощенные парсеры отказываются обрабатывать такие сообщения, требуя «чистые» теги без префиксов.
В этой статье мы подробно разберем, почему возникают такие префиксы, и рассмотрим несколько способов их устранения — от простых «хаков» до методологически правильных подходов с использованием штатных механизмов платформы 1С.
Рассмотрим ситуацию: вы используете метод ЗаписатьНачалоЭлемента и передаете в него два параметра: имя тега и URI пространства имен. Например:
ЗаписьXML.ЗаписатьНачалоЭлемента("transfer", "http://ttt.com/ttt");
Для платформы 1С это сигнал о том, что элемент transfer принадлежит указанному пространству имен. Однако, если ранее в документе не было объявлено соответствие этого URI какому-либо префиксу (включая пустой префикс по умолчанию), система вынуждена создать технический префикс самостоятельно, чтобы гарантировать валидность документа. Так в вашем XML появляется запись вида <d3p1:transfer xmlns:d3p1="http://ttt.com/ttt">.
Проанализируем ситуацию подробнее. С точки зрения спецификации XML Namespaces, запись без префикса возможна только тогда, когда пространство имен объявлено как default namespace (через атрибут xmlns без двоеточия). Выясним, как заставить 1С генерировать именно такой формат.
Это самый правильный и надежный способ управления префиксами. Мы можем явно указать системе, что для конкретного URI должен использоваться «пустой» префикс. Разберем по шагам, как это реализовать.
Во-первых, необходимо создать корневой элемент или родительский узел, в котором будет объявлено пространство имен. Во-вторых, нужно использовать метод ЗаписатьСоответствиеПространстваИмен, передав в качестве первого параметра пустую строку.
// Создаем объект записи
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// Записываем начало корневого элемента (пока без URI)
ЗаписьXML.ЗаписатьНачалоЭлемента("root");
// Объявляем пространство имен по умолчанию (пустой префикс)
// Первый параметр - пустая строка, второй - ваш URI
ЗаписьXML.ЗаписатьСоответствиеПространстваИмен("", "http://www.ttt.com/ttt");
// Теперь записываем вложенный элемент, указывая тот же URI
// 1С увидит, что для этого URI уже назначен пустой префикс, и не будет создавать d3p1
ЗаписьXML.ЗаписатьНачалоЭлемента("transfer", "http://www.ttt.com/ttt");
ЗаписьXML.ЗаписатьАтрибут("version", "01.05.00");
ЗаписьXML.ЗаписатьКонецЭлемента(); // закрываем transfer
ЗаписьXML.ЗаписатьКонецЭлемента(); // закрываем root
Результат = ЗаписьXML.Закрыть();
В результате мы получим структуру, где элемент transfer будет записан без лишних букв в имени тега, так как он наследует пространство имен по умолчанию от родителя или объявляет его сам.
Если структура XML сложная и вам нужно гарантировать отсутствие префиксов для определенных пространств на протяжении всей записи, воспользуемся методом УстановитьПрефикс. Рассмотрим пример:
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\request.xml");
// Устанавливаем соответствие ПЕРЕД записью элементов
ЗаписьXML.УстановитьПрефикс("", "http://www.ttt.com/ttt");
// Теперь при записи элемента с этим URI префикс d3p1 не появится
ЗаписьXML.ЗаписатьНачалоЭлемента("transfer", "http://www.ttt.com/ttt");
// ... запись атрибутов ...
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.Закрыть();
Метод УстановитьПрефикс работает как «подсказка» для парсера: всякий раз, когда встречается указанный URI, использовать именно этот префикс (в нашем случае — пустой).
Как было отмечено в обсуждении на форуме, существует «хакерский» способ — записать xmlns как обычный атрибут. Посмотрим на пример кода:
// В методе ЗаписатьНачалоЭлемента НЕ указываем URI вторым параметром
ЗаписьXML.ЗаписатьНачалоЭлемента("transfer");
// Записываем пространство имен как обычный текстовый атрибут
ЗаписьXML.ЗаписатьАтрибут("xmlns", "http://www.ttt.com/ttt");
ЗаписьXML.ЗаписатьАтрибут("version", "01.05.00");
ЗаписьXML.ЗаписатьКонецЭлемента();
Важное предостережение: Хотя этот способ часто работает для простых документов, он считается небезопасным. Объект ЗаписьXML может не отследить такое «ручное» объявление. Если внутри этого элемента вы попытаетесь создать дочерние узлы через штатный механизм пространств имен, платформа может создать конфликт имен или продублировать объявления. Используйте этот метод только в самых крайних случаях, когда другие способы не помогают «подружиться» с принимающим веб-сервисом.
Если вы формируете сложные SOAP-запросы, лучшим решением будет использование XDTO (XML Data Transfer Objects). Платформа 1С берет на себя всю работу по управлению префиксами на основе схемы XSD. Проанализируем преимущества этого подхода:
elementFormDefault="qualified", но при этом для корневого пакета настроено отсутствие префиксов, 1С сама сформирует правильный XML.Пример записи XDTO в ЗаписьXML без лишних префиксов:
// Предположим, у нас есть объект XDTO 'МойОбъект'
// и ФабрикаXDTO, инициализированная нужной схемой.
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// При сериализации можно управлять настройками пространств имен
ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, МойОбъект, , , , НазначениеТипаXML.Явное);
Подведем итоги нашего исследования. Если внешняя система «ругается» на префиксы d3p1, выполните следующие действия:
ЗаписатьНачалоЭлемента. Если вы передаете URI, 1С обязана обеспечить его идентификацию.ЗаписатьСоответствиеПространстваИмен("", "URI") сразу после открытия корневого тега, чтобы назначить пустой префикс по умолчанию.WSПрокси или HTTPСоединение. Иногда префиксы добавляются на уровне конверта (Envelope), что требует настройки заголовков.ЗаписьXML — залог того, что ваш файл будет соответствовать мировым стандартам, даже если префиксы кажутся вам избыточными.Разбор этих методов показывает, что платформа 1С предоставляет достаточно гибкие инструменты для работы с XML любой сложности. Главное — понимать механику наследования пространств имен и вовремя подсказывать системе, какой префикс вы ожидаете увидеть в итоговом документе.