Как записать секцию CDATA в XML одной строкой без лишних пробелов и переносов

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

При интеграции 1С с внешними системами, особенно с ГИС МТ (Честный Знак), разработчики часто сталкиваются с жесткими требованиями к структуре XML-файла. Одной из специфических проблем является автоматическое форматирование объекта ЗаписьXML, которое добавляет отступы и переводы строк там, где их быть не должно — например, вокруг секции CDATA. В этой статье мы разберем, почему это происходит и какими способами можно добиться записи данных строго в одну строку: <ki><![CDATA[123]]></ki>.

Почему стандартные методы добавляют лишние символы?

Разберем ситуацию: когда мы используем стандартную последовательность методов ЗаписатьНачалоЭлемента, ЗаписатьСекциюCDATA и ЗаписатьКонецЭлемента, объект ЗаписьXML ориентируется на свои внутренние настройки форматирования. Если в параметрах записи включен отступ (что часто является поведением по умолчанию для удобства чтения человеком), платформа автоматически вставляет символы перевода строки и табуляции для формирования «лесенки» тегов.

Проблема в том, что для систем автоматизированного учета, таких как ГИС МТ, любой символ внутри или рядом с тегом, содержащим код маркировки, считается частью значения. Лишний пробел приведет к тому, что подпись файла станет неверной, а код маркировки — нечитаемым.

Решение 1: Использование метода ЗаписатьБезОбработки

Проанализируем самый простой и эффективный способ обхода логики форматирования. Вместо того чтобы позволять платформе самой закрывать теги, мы можем передать готовую строку. Как было отмечено в обсуждении, если записывать только содержимое через ЗаписатьБезОбработки, закрывающий тег все равно может «улететь» на новую строку из-за предшествующего вызова ЗаписатьНачалоЭлемента.

Правильный подход заключается в том, чтобы сформировать весь узел целиком в виде строки и передать его в поток одним вызовом. Рассмотрим пример кода:


// Предположим, ЗаписьXML уже инициализирована
ЗначениеКИ = "0104600000000000215Yn<G93"; // Пример кода маркировки
СтрокаУзла = "<ki><![CDATA[" + ЗначениеКИ + "]]></ki>";
ЗаписьXML.ЗаписатьБезОбработки(СтрокаУзла);

В этом случае 1С вставляет строку «как есть», не пытаясь анализировать вложенность тегов внутри этой строки. Это гарантирует отсутствие нежелательных переносов внутри блока <ki>.

Решение 2: Тонкая настройка ПараметрыЗаписиXML

Если нам нужно сохранить структуру документа, но полностью избавиться от «красивого» форматирования во всем файле, необходимо правильно инициализировать объект ПараметрыЗаписиXML. Выясним, какие свойства на это влияют.

Посмотрим на реализацию настройки параметров:


ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь); // Ложь отключает форматирование
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, ПараметрыЗаписи);

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

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

Решение 3: Использование объектной модели DOM

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

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

  1. Создаем объект ДокументDOM.
  2. Создаем элемент ki через СоздатьЭлемент.
  3. Создаем секцию CDATA через СоздатьСекциюCDATA и добавляем её внутрь элемента.
  4. Используем ЗаписьDOM для выгрузки результата.

Пример программной реализации:


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

УзелКИ = ДокDOM.СоздатьЭлемент("ki");
СекцияCDATA = ДокDOM.СоздатьСекциюCDATA("Данные_КИ_Без_Пробелов");
УзелКИ.ДобавитьПодчиненный(СекцияCDATA);
Корень.ДобавитьПодчиненный(УзелКИ);

// Записываем DOM в файл без форматирования
ЗаписьDOM = Новый ЗаписьDOM;
ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, ПараметрыЗаписи);
ЗаписьDOM.Записать(ДокDOM, ЗаписьXML);
ЗаписьXML.Закрыть();

Метод ЗаписьDOM.Записать в сочетании с отключенным форматированием в ЗаписьXML дает 100% гарантию того, что содержимое CDATA и обрамляющие его теги не будут разделены пробельными символами.

Особенности работы с ГИС МТ (Честный Знак)

Важно понимать причину такой чувствительности системы. Честный Знак использует XSD-схемы, где для многих полей определен тип string с ограничениями или регулярными выражениями. Если в поле, предназначенное для кода маркировки (DataMatrix), попадает символ \n (перенос строки) или \t (табуляция), система выдаст ошибку "Некорректный формат кода".

Кроме того, если вы используете усиленную квалифицированную электронную подпись (УКЭП) для подписания XML-документа, любое изменение хотя бы одного байта в файле (включая невидимые пробелы) сделает подпись невалидной. Поэтому использование метода ЗаписатьБезОбработки или полное отключение форматирования в параметрах — это не просто "экономия места", а техническая необходимость.

Резюмируем: для получения компактной записи в одну строку лучше всего использовать ручное формирование строки тега через ЗаписатьБезОбработки("<tag>...</tag>") или полностью отключать форматирование в объекте ПараметрыЗаписиXML.

← На главную