Как решить проблему с выгрузкой апострофа в XML в 1С

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

При интеграции систем 1С с внешними сервисами, государственными порталами (такими как СФР, ФТС, МЧД) или банковскими API разработчики часто сталкиваются с жесткими требованиями к формату XML-файлов. Одной из распространенных проблем является обработка символа апострофа (одинарной кавычки '). В этой статье мы подробно разберем, почему стандартные механизмы 1С отказываются заменять апостроф на сущность ', почему ручная замена приводит к ошибкам и как правильно решить эту задачу без искажения исходных данных.

Выясняем причину: почему ЗаписьXML и XMLСтрока игнорируют апостроф

Для начала проанализируем поведение самой платформы 1С. Многие разработчики ожидают, что при вызове методов ЗаписьXML.ЗаписатьТекст() или функции XMLСтрока() все спецсимволы будут автоматически преобразованы в соответствующие XML-сущности. Однако с апострофом этого не происходит. Почему?

Поведение платформы 1С строго соответствует официальному стандарту консорциума W3C для XML. Согласно спецификации, в XML существует 5 предопределенных сущностей:

Согласно стандарту, обязательному экранированию в текстовых узлах (внутри тегов) подлежат только символы < и &. Символы кавычек и апострофов обязаны экранироваться только внутри значений атрибутов, и то лишь в тех случаях, когда они совпадают с символом-ограничителем самого атрибута (например, если значение атрибута обернуто в одинарные кавычки: name='O&apos;Connor').

Внутри обычного текстового элемента запись вида <name>Об'єм</name> является абсолютно валидной. Платформа 1С оптимизирует размер файла и быстродействие, поэтому не выполняет избыточную замену символа ' на &apos;. Но как быть, если принимающая сторона (парсер сторонней системы) написана некорректно или использует жесткие регулярные выражения и требует обязательного наличия &apos;?

Разбор ошибок и неэффективных решений с форума

Рассмотрим типичные ошибки, которые совершают разработчики при попытке обойти это ограничение:

  1. Замена апострофа на типографский аналог (косой апостроф). В сообщении форума было предложено заменить прямой апостроф на правый одинарный кавычку: СтрЗаменить(ТекстТега, "'", "’"). С точки зрения прохождения валидации XML-схемы это сработает. Однако этот способ искажает исходные данные. Для базы данных «Об'єм» и «Об’єм» — разные строки. Если принимающая система производит поиск по ключевым полям (например, названия организаций, фамилии или адреса), автоматическое сопоставление данных завершится ошибкой.
  2. Использование некорректных ASCII-кодов. Попытка использовать Символ(37) приведет к тому, что вместо апострофа в XML запишется знак процента % (например, «Об%єм»), так как код 37 в таблице ASCII соответствует именно этому символу. Прямой апостроф имеет код 39 (Символ(39)), но его простая подстановка в текстовую переменную не изменит поведения ЗаписьXML.
  3. Прямая замена на сущность в коде 1С. Если мы попытаемся выполнить замену СтрЗаменить(ТекстТега, "'", "&apos;") перед записью в XML, то на выходе получим некорректную строку вида &amp;apos;. Это происходит потому, что объект ЗаписьXML видит символ амперсанда & во вновь созданной строке и послушно экранирует его, превращая в &amp;.

Правильный способ №1: Пост-обработка сформированного XML-документа

Самый надежный и корректный способ гарантированно получить сущность &apos; (или её числовой эквивалент &#39;) в финальном файле — это выполнить замену символов после того, как XML-документ был полностью сгенерирован платформой 1С. Таким образом, мы обойдем встроенный парсер ЗаписьXML и избежим двойного экранирования амперсанда.

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

  1. Инициализируем запись XML в строку (в оперативную память), а не напрямую в файл.
  2. Формируем структуру документа стандартными методами платформы.
  3. Закрываем объект записи и получаем готовую XML-строку.
  4. Применяем функцию СтрЗаменить для принудительной замены одиночной кавычки на требуемую сущность.
  5. Записываем измененный текст в итоговый файл на диске с помощью объекта ЗаписьТекста с указанием нужной кодировки (обычно UTF-8).

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


// Шаг 1. Инициализируем запись XML в память
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписьXML.ЗаписатьОбъявлениеXML();

// Шаг 2. Формируем структуру XML-документа
ЗаписьXML.ЗаписатьНачалоЭлемента("Данные");
ЗаписьXML.ЗаписатьНачалоЭлемента("Параметр");

ТекстТега = "Об'єм"; // Исходная строка с апострофом
ЗаписьXML.ЗаписатьТекст(ТекстТега);

ЗаписьXML.ЗаписатьКонецЭлемента(); // Параметр
ЗаписьXML.ЗаписатьКонецЭлемента(); // Данные

// Шаг 3. Получаем XML-текст из объекта записи
ТекстXML = ЗаписьXML.Закрыть();

// Шаг 4. Выполняем замену апострофа на сущность &apos; (или ее числовой код ')
// Некоторые старые парсеры лучше поддерживают числовой код '
ТекстXML = СтрЗаменить(ТекстXML, "'", "&apos;");

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

Этот метод гарантирует, что структура XML останется абсолютно валидной, а все апострофы будут корректно экранированы в соответствии с жесткими требованиями внешней системы.

Правильный способ №2: Использование секций CDATA

Если принимающая сторона способна корректно обрабатывать спецификацию XML в полном объеме, можно использовать механизм секций CDATA. Данные, помещенные в такую секцию, не анализируются XML-процессором на наличие спецсимволов. Это позволяет передавать тексты, содержащие апострофы, кавычки, амперсанды и знаки сравнения, в их первозданном виде.

Проанализируем пример кода с использованием метода ЗаписатьСекциюCDATA:


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, "UTF-8");
ЗаписьXML.ЗаписатьОбъявлениеXML();

ЗаписьXML.ЗаписатьНачалоЭлемента("Данные");
ЗаписьXML.ЗаписатьНачалоЭлемента("Параметр");

ТекстТега = "Об'єм";
// Записываем значение внутри блока CDATA
ЗаписьXML.ЗаписатьСекциюCDATA(ТекстТега);

ЗаписьXML.ЗаписатьКонецЭлемента(); // Параметр
ЗаписьXML.ЗаписатьКонецЭлемента(); // Данные

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

В результате работы этого кода в XML-файле сформируется следующая структура:

<Параметр><![CDATA[Об'єм]]></Параметр>

Этот подход избавляет от необходимости ручной замены строк и обеспечивает стопроцентную сохранность передаваемых данных. Однако перед его внедрением обязательно убедитесь, что веб-сервис или парсер на стороне получателя умеет корректно извлекать данные из секций CDATA.

← На главную