Как в ЗаписьXML отключить сокращение пустых узлов

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

При выгрузке данных из 1С в формате XML разработчики часто сталкиваются с особенностью стандартного объекта ЗаписьXML: пустые узлы автоматически записываются в сокращенном виде. Например, вместо ожидаемого полного тега <units></units> платформа формирует самозакрывающийся тег <units/>. Несмотря на то, что оба варианта соответствуют стандартам XML, многие внешние системы (особенно устаревшие версии Oracle, специфические парсеры или системы, использующие регулярные выражения для чтения) не могут корректно обработать сокращенную запись. В этой статье мы подробно разберем, как заставить 1С формировать полные теги.

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

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

Способ 1. Использование объекта ПреобразованиеККаноническомуXML

Начиная с версии платформы 8.3.12, разработчикам стал доступен современный механизм канонизации. Рассмотрим подробнее этот подход. Канонический XML — это форма представления документа, исключающая любые вариации (включая сокращенные теги). Это наиболее «чистый» и официальный способ решения проблемы.

Разберем по шагам процесс реализации:

  1. Сначала формируем обычный XML-файл или записываем его в строку.
  2. Загружаем полученный результат в объект ЧтениеXML.
  3. Используем ПреобразованиеККаноническомуXML для получения итогового потока данных.

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


// Сначала записываем обычный XML
ПутьКФайлу = "C:\temp\data.xml";
Запись = Новый ЗаписьXML;
Запись.ОткрытьФайл(ПутьКФайлу, "UTF-8");
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("root");
Запись.ЗаписатьНачалоЭлемента("units");
Запись.ЗаписатьКонецЭлемента(); // Здесь будет <units/>
Запись.ЗаписатьКонецЭлемента();
Запись.Закрыть();

// Теперь преобразуем его в канонический вид
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ПутьКФайлу);

Преобразование = Новый ПреобразованиеККаноническомуXML;
// Указываем тип канонизации (без сокращенных узлов)
ЗаписьКанон = Новый ЗаписьXML;
ЗаписьКанон.ОткрытьФайл("C:\temp\canonical_data.xml", "UTF-8");

Преобразование.Выполнить(Чтение, ЗаписьКанон);
ЗаписьКанон.Закрыть();
Чтение.Закрыть();

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

Способ 2. Использование устаревшего объекта КаноническаяЗаписьXML

Если вы работаете на более старых релизах платформы (ниже 8.3.12) или поддерживаете исторический код, можно встретить объект КаноническаяЗаписьXML. Хотя он признан устаревшим, он все еще присутствует во многих конфигурациях и выполняет ту же функцию — принудительно разворачивает теги.

Проанализируем пример использования этого объекта:


ЗаписьXML = Новый КаноническаяЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ЗаписьXML.УстановитьСтроку(ТипКаноническогоXML.КаноническийXML);
// Далее работаем как с обычной ЗаписьXML
ЗаписьXML.ЗаписатьНачалоЭлемента("units");
ЗаписьXML.ЗаписатьКонецЭлемента();
РезультатСтрокой = ЗаписьXML.Закрыть();

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

Способ 3. Принудительная вставка пустой секции CDATA

Существует «хитрый» способ обмануть сериализатор 1С. Если внутри элемента есть какое-то содержимое, платформа не может его сократить. Однако добавление простого пробела или пустой строки ЗаписатьТекст("") часто игнорируется оптимизатором. В этом случае на помощь приходит секция CDATA.

Посмотрим, как это реализовать:


ЗаписьXML.ЗаписатьНачалоЭлемента("units");
ЗаписьXML.ЗаписатьСекциюCDATA(""); 
ЗаписьXML.ЗаписатьКонецЭлемента();

В итоге мы получим <units><![CDATA[]]></units>. Большинство систем, включая Oracle, воспринимают это как пустую строку, но при этом тег остается развернутым. Это решение является быстрым «костылем», если канонизация по каким-то причинам недоступна или нежелательна.

Способ 4. Использование внешних COM-объектов (MSXML)

В ситуациях, когда стандартные средства 1С не дают нужной гибкости, мы можем обратиться к возможностям Windows и использовать объект MSXML2.DOMDocument. Этот метод подходит для работы на Windows-серверах.

Рассмотрим пример формирования узла через COM:


xmlDoc = Новый COMОбъект("MSXML2.DOMDocument.6.0");
root = xmlDoc.createElement("root");
xmlDoc.appendChild(root);

unitsNode = xmlDoc.createElement("units");
// Явно задаем пустое текстовое содержимое
unitsNode.text = ""; 
root.appendChild(unitsNode);

// При сохранении MSXML обычно сохраняет полные теги для текстовых узлов
xmlDoc.save("C:\temp\msxml_data.xml");

Способ 5. Постобработка итоговой строки (RegExp)

Если файл небольшой, мы можем применить метод «грубой силы» — заменить сокращенные теги на полные после того, как XML уже сформирован в строку. Однако делать это простым СтрЗаменить крайне опасно, так как символы /> могут встретиться внутри значений атрибутов.

Разберем правильный подход с использованием регулярных выражений:


Функция РазвернутьТеги(СтрXML)
    RegExp = Новый COMОбъект("VBScript.RegExp");
    RegExp.IgnoreCase = Истина;
    RegExp.Global = Истина;
    RegExp.MultiLine = Истина;
    
    // Шаблон ищет теги вида <ИмяТега /> или <ИмяТега ... />
    RegExp.Pattern = "<([a-zA-Z0-9_:]+)([^>]*)/>";
    
    // Заменяем на <ИмяТега ...></ИмяТега>
    Возврат RegExp.Replace(СтрXML, "<$1$2></$1>");
КонецФункции

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

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

Проанализировав все доступные варианты, мы рекомендуем придерживаться следующей стратегии:

1. Для новых конфигураций (Платформа 8.3.12+): используйте ПреобразованиеККаноническомуXML. Это самый надежный и стандартный способ, который гарантирует корректность структуры документа.
2. Для оперативного решения: попробуйте метод с ЗаписатьСекциюCDATA(""). Он требует минимум изменений в коде и часто решает проблему несовместимости с Oracle без лишних сложностей.
3. Если важна производительность: избегайте постобработки строковыми функциями для файлов размером более 10-20 Мб, так как это значительно увеличит потребление памяти.

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

← На главную