Как в 1С при записи XML получить полный закрывающий тег вместо самозакрывающегося

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

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

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

Выясним причину: почему 1С сокращает теги

Для работы с XML платформа 1С использует объект ЗаписьXML, который базируется на системных библиотеках операционной системы (обычно это MSXML в Windows или libxml2 в Linux). Эти библиотеки жестко следуют спецификации XML. Оптимизация пустого узла до самозакрывающегося тега — это стандартное поведение. К сожалению, в объекте ПараметрыЗаписиXML не существует свойства типа "ЗапретитьСокращенныеТеги". Поэтому нам придется применять обходные пути.

Важное уточнение по терминологии: в обсуждениях часто путают атрибуты и элементы. Атрибуты — это свойства внутри тега (например, <UNIT type="weight">), и они не могут иметь закрывающих тегов. В нашем случае речь идет исключительно об элементах (узлах) XML-дерева.

Способ 1. Использование пустого комментария

Рассмотрим самый "хитрый" и в то же время чистый способ. Чтобы обмануть парсер и заставить его считать, что элемент не пуст, мы можем записать внутрь него пустой комментарий. С точки зрения данных это ничего не меняет (большинство систем игнорируют комментарии), но для ЗаписьXML элемент перестает быть пустым.

Разберем этот метод на примере кода:


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл("C:\temp\data.xml", "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();

ЗаписьXML.ЗаписатьНачалоЭлемента("PAYD");
ЗаписьXML.ЗаписатьТекст("test");
ЗаписьXML.ЗаписатьКонецЭлемента(); // Будет <PAYD>test</PAYD>

// Применяем хитрость с комментарием для узла UNIT
ЗаписьXML.ЗаписатьНачалоЭлемента("UNIT");
ЗаписьXML.ЗаписатьКомментарий(""); 
ЗаписьXML.ЗаписатьКонецЭлемента(); 

ЗаписьXML.Закрыть();

В результате в файле мы увидим строку: <UNIT><!----></UNIT>. Если принимающая сторона обрабатывает XML стандартным парсером, она просто не заметит комментарий, но увидит желанную структуру тегов.

Способ 2. Объектная модель документа (DOM)

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

Рассмотрим по шагам, как это реализовать:


// Создаем основу документа
ДокументDOM = Новый ДокументDOM;
КорневойУзел = ДокументDOM.СоздатьЭлемент("Data");
ДокументDOM.ДобавитьДочерний(КорневойУзел);

// Создаем элемент UNIT
ЭлементUnit = ДокументDOM.СоздатьЭлемент("UNIT");
// Явно создаем текстовый узел с пустой строкой
ПустойТекст = ДокументDOM.СоздатьТекстовыйУзел("");
ЭлементUnit.ДобавитьДочерний(ПустойТекст);

КорневойУзел.ДобавитьДочерний(ЭлементUnit);

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

РезультатСтрокой = ЗаписьXML.Закрыть();

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

Способ 3. Пост-обработка текстового результата (Самый надежный)

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

Посмотрим на пример реализации:


// 1. Формируем XML в строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
// ... логика записи элементов ...
ЗаписьXML.ЗаписатьНачалоЭлемента("UNIT");
ЗаписьXML.ЗаписатьКонецЭлемента();
ТекстXML = ЗаписьXML.Закрыть();

// 2. Выполняем замену
// Важно: делайте замену только для конкретных тегов, чтобы не испортить структуру
ТекстXML = СтрЗаменить(ТекстXML, "<UNIT/>", "<UNIT></UNIT>");

// 3. Сохраняем в файл или отправляем в API

Важный момент: использование СтрЗаменить оправдано, если вы точно знаете имена тегов, которые нужно развернуть. Массовая замена всех вхождений /> на полные закрывающие теги с помощью регулярных выражений требует осторожности, чтобы не нарушить валидность документа.

Способ 4. Использование метода "ЗаписатьБезОбработки"

Этот метод превращает объект ЗаписьXML в обычный текстовый редактор. Мы можем вручную вставить в поток любую строку. Это дает полный контроль над результатом, но лишает нас преимуществ автоматического экранирования спецсимволов.

Проанализируем ситуацию:


ЗаписьXML.ЗаписатьНачалоЭлемента("ROOT");
// Пишем тег вручную
ЗаписьXML.ЗаписатьБезОбработки("<UNIT></UNIT>");
ЗаписьXML.ЗаписатьКонецЭлемента();

Используйте этот метод только в крайних случаях, так как при записи сложных данных (например, строк с символами & или <) вам придется самостоятельно заботиться об их преобразовании в сущности &amp; и &lt;.

Резюме и рекомендации

Подведем итоги нашего исследования:

  1. Лучшая практика: Попробовать убедить владельцев принимающей стороны исправить их парсер, так как <Tag/> является стандартом.
  2. Если исправить нельзя: Используйте Способ 1 (Пустой комментарий) как самый быстрый и наименее ресурсозатратный.
  3. Для сложных структур: Подойдет Способ 2 (DOM), он позволит сохранить логику работы с объектами.
  4. Гарантированный результат: Дает Способ 3 (Текстовая замена), так как он работает уже с финальной строкой, где платформенные оптимизации завершены.

Правильный выбор метода зависит от объема выгружаемого файла и того, насколько критично для вас сохранение "чистоты" XML-кода.

← На главную