Как убрать лишний атрибут xmlns="" при формировании XML в 1С 7.7

Программист 1С v7.7
← На главную

При разработке механизмов интеграции (например, с ЕГАИС через УТМ) программисты часто сталкиваются со специфическим поведением парсера MSXML 6.0. Суть проблемы заключается в том, что при создании дочернего узла без явного указания пространства имен внутри родительского узла, имеющего пространство имен по умолчанию, система автоматически добавляет атрибут xmlns="". Это делается для соблюдения стандартов XML, но принимающая сторона (УТМ) часто выдает ошибку, так как не ожидает этого атрибута. В данной статье мы разберем несколько эффективных способов решения этой задачи в среде 1С:Предприятие 7.7.

Причина возникновения проблемы

Прежде всего, проанализируем ситуацию. Когда мы используем MSXML2.DOMDocument.6.0, парсер строго следит за соответствием узлов заявленным пространствам имен (Namespaces). Если у корневого элемента задан xmlns="http://some-uri", а дочерний элемент создается простым методом createElement("name"), парсер считает, что новый элемент относится к "пустому" пространству имен. Чтобы это зафиксировать в итоговом файле, он добавляет xmlns="".

Решение 1: Правильное использование метода createNode

Самый "чистый" технический способ — это создание узла с явным указанием того же URI пространства имен, которое используется в родительском элементе. Рассмотрим подробнее, как это реализовать. Вместо createElement нам необходимо использовать createNode, где вторым параметром передается имя узла, а третьим — URI пространства имен.

Посмотрим на пример кода:


// Создаем объект DOM
XML_DOM = СоздатьОбъект("MSXML2.DOMDocument.6.0");
// ... формирование заголовка и корня ...

// Допустим, URI нашего пространства имен задан в переменной
НашURI = "http://fsrar.ru/WEGAIS/QueryFilter";

// Вместо XML_DOM.createElement("bc") используем:
XML_BC = XML_DOM.createNode(1, "bc", НашURI);
XML_QF.appendChild(XML_BC);
XML_BC.text = "101200026723...";

В этом случае парсер поймет, что элемент bc принадлежит к тому же пространству имен, что и родительский QueryFilter, и лишний атрибут xmlns="" не появится.

Решение 2: Текстовая сборка XML через FileSystemObject

Если структура XML сложная или парсер MSXML продолжает вести себя непредсказуемо, мы можем применить метод прямой текстовой записи. Этот способ гарантирует, что в файл попадет ровно то, что мы написали, без самодеятельности со стороны системных библиотек. Для работы с файлами удобно использовать объект Scripting.FileSystemObject.

Рассмотрим пошагово реализацию этого метода:

  1. Создаем объект для работы с файловой системой.
  2. Открываем текстовый поток для записи.
  3. Последовательно пишем строки XML-структуры.

Пример реализации функции выгрузки:


Функция ВыгрузитьВТекст(ИмяФайла, ТЗ)
    ФСО = СоздатьОбъект("Scripting.FileSystemObject");
    ТекстСтрим = ФСО.OpenTextFile(ИмяФайла, 2, 1, 0); // 2 - запись, 1 - создать если нет, 0 - ANSI
    
    ТекстСтрим.WriteLine("<?xml version=""1.0"" encoding=""UTF-8""?>");
    ТекстСтрим.WriteLine("<ns:Documents xmlns:ns=""http://fsrar.ru/WEGAIS/WB_DOC_SINGLE_01"" xmlns=""http://fsrar.ru/WEGAIS/QueryFilter"" Version=""1.0"">");
    
    // ... запись Owner и других узлов ...
    
    ТекстСтрим.WriteLine("  <ns:Document>");
    ТекстСтрим.WriteLine("    <ns:QueryFilter>");
    
    ТЗ.ВыбратьСтроки();
    Пока ТЗ.ПолучитьСтроку() = 1 Цикл
        ТекстСтрим.WriteLine("      <bc>" + СокрЛП(ТЗ.ШК) + "</bc>");
    КонецЦикла;
    
    ТекстСтрим.WriteLine("    </ns:QueryFilter>");
    ТекстСтрим.WriteLine("  </ns:Document>");
    ТекстСтрим.WriteLine("</ns:Documents>");
    ТекстСтрим.Close();
КонецФункции

Решение 3: Использование шаблонов (Replace-метод)

Для упрощения поддержки сложных XML-файлов удобно использовать текстовые шаблоны. Мы создаем эталонный файл, где на месте динамических данных вставляем маркеры (например, %DOCNUM%), а затем программно заменяем их на реальные значения.

Проанализируем ситуацию, когда у нас есть повторяющиеся блоки (строки товаров или марок). В этом случае мы используем два шаблона: основной и шаблон строки.


// Шаблон строки
ШаблонBC = "<bc>%MARK%</bc>";
ВсеМарки = "";

ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    ВсеМарки = ВсеМарки + СтрЗаменить(ШаблонBC, "%MARK%", СокрЛП(ТЗ.ШК)) + РазделительСтрок;
КонецЦикла;

// Вставляем накопленный блок в основной шаблон
ИтоговыйXML = СтрЗаменить(ОсновнойШаблон, "%MARK_LIST%", ВсеМарки);

Важный момент: при использовании текстовых методов нужно самостоятельно следить за экранированием спецсимволов XML (амперсанд, кавычки, угловые скобки). Для этого напишем вспомогательную функцию:


Функция Экранировать(Стр)
    Рез = СтрЗаменить(Стр, "&", "&amp;");
    Рез = СтрЗаменить(Рез, "<", "&lt;");
    Рез = СтрЗаменить(Рез, ">", "&gt;");
    Рез = СтрЗаменить(Рез, """", "&quot;");
    Возврат Рез;
КонецФункции

Проблема кодировки UTF-8 в 1С 7.7

Выясним причину проблем с кодировкой. 1С 7.7 "из коробки" плохо работает с UTF-8, предпочитая Windows-1251. Если мы просто запишем файл через объект Текст, кодировка будет неверной. Чтобы корректно сохранить XML в UTF-8, воспользуемся объектом ADODB.Stream.

Разберем алгоритм перекодировки файла:


Процедура СохранитьВUTF8(ИмяФайла, ТекстДанных)
    Стрим = СоздатьОбъект("ADODB.Stream");
    Стрим.Type = 2; // adTypeText
    Стрим.Charset = "utf-8";
    Стрим.Open();
    Стрим.WriteText(ТекстДанных);
    Стрим.SaveToFile(ИмяФайла, 2); // adSaveCreateOverWrite
    Стрим.Close();
КонецПроцедуры

Пост-обработка сформированного DOM

Если вы уже написали большой объем кода на базе DOMDocument и не хотите его переделывать, можно применить "хирургическое вмешательство": сформировать XML, сохранить его во временный файл, а затем программно удалить подстроку xmlns="".


// Сохраняем результат работы DOM
XML_DOM.save(ПутьКФайлу);

// Читаем файл как текст и правим
ТекстФайл = СоздатьОбъект("Текст");
ТекстФайл.Открыть(ПутьКФайлу);
ВесьТекст = "";
Для Сч = 1 По ТекстФайл.КоличествоСтрок() Цикл
    Стр = ТекстФайл.ПолучитьСтроку(Сч);
    Стр = СтрЗаменить(Стр, " xmlns=""""", "");
    ВесьТекст = ВесьТекст + Стр + РазделительСтрок;
КонецЦикла;

// Записываем обратно через ADODB.Stream для сохранения UTF-8
СохранитьВUTF8(ПутьКФайлу, ВесьТекст);

Резюме

Мы рассмотрели различные подходы к формированию "чистого" XML в 1С 7.7. Для новых задач мы рекомендуем использовать либо правильное указание Namespace URI в методе createNode, либо текстовые шаблоны с последующим сохранением через ADODB.Stream. Текстовый метод является наиболее гибким, так как он полностью исключает влияние настроек парсера MSXML на структуру итогового документа.

← На главную