При работе с обменом данными через XML — будь то типовой обмен или выгрузка и загрузка данных XML с дополнительными опциями (для этого есть универсальная выгрузка и загрузка данных через XML) — разработчики могут столкнуться с ошибкой вида «Текст XML содержит недопустимый символ в позиции...».
Такая ошибка означает, что в формируемый XML-документ попал символ, который не разрешен спецификацией XML. При этом важно различать две разные группы символов:
В XML 1.0 из управляющих символов с кодами ниже 32 разрешены только:
	;
;
.Остальные управляющие символы в диапазонах U+0000–U+0008, U+000B–U+000C и U+000E–U+001F в XML 1.0 запрещены.
Один из частых примеров — символ char(29), то есть Group Separator, GS, U+001D. Он используется в штрихкодах GS1 как разделитель элементов данных и может встречаться при интеграции с ЦРПТ, сканерами штрихкодов и системами ЭДО — например, при использовании интеграции с ЦРПТ и GS1 через XML и ЭДО.
Важно: заменить настоящий символ U+001D на строку  нельзя. Такая числовая ссылка также является недопустимой в XML 1.0, поскольку она указывает на запрещенный символ. XML-парсер должен отклонить такой документ.
Отдельную группу составляют символы, которые разрешены в XML, но имеют специальное значение в его синтаксисе:
< записывается как <;> при необходимости записывается как >;& записывается как &;' в значении атрибута можно записать как ';" в значении атрибута можно записать как ".Символы < и & необходимо экранировать в текстовом содержимом XML. Кавычки и апострофы обязательно экранируются только тогда, когда они совпадают с ограничителем значения атрибута.
При формировании XML не следует вручную собирать документ путем конкатенации строк. Для этого лучше использовать встроенный объект ЗаписьXML. Метод ЗаписатьТекст() самостоятельно экранирует допустимые служебные символы XML, например < и &.
ИсходныйТекст = "Наименование: Болт & Гайка, размер < 10 мм";
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписьXML.ЗаписатьНачалоДокумента();
ЗаписьXML.ЗаписатьНачалоЭлемента("Данные");
ЗаписьXML.ЗаписатьТекст(ИсходныйТекст);
ЗаписьXML.ЗаписатьКонецЭлемента();
ЗаписьXML.ЗаписатьКонецДокумента();
СтрокаXML = ЗаписьXML.Закрыть();
В сформированном документе служебные символы будут экранированы автоматически. Однако ЗаписьXML не может превратить запрещенный управляющий символ в допустимый. Поэтому такие символы необходимо удалить или заменить до вызова ЗаписатьТекст().
Если в конфигурации используется Библиотека стандартных подсистем, для предварительной очистки можно применять функции общего модуля СериализацияXML.
// Заменяем недопустимые символы пробелами
ОчищенныйТекст = СериализацияXML.ЗаменитьНедопустимыеСимволыXML(
ИсходныйТекст,
" "
);
// Либо полностью удаляем недопустимые символы
ОчищенныйТекст = СериализацияXML.УдалитьНедопустимыеСимволыXML(
ИсходныйТекст
);
Выбор между заменой и удалением зависит от назначения данных. Для обычного текста управляющий символ чаще всего можно удалить или заменить пробелом. Для штрихкодов GS1 простое удаление разделителя может изменить смысл данных, поэтому следует использовать обратимое преобразование.
Если принимающая сторона ожидает исходный GS1-код, символ U+001D можно временно заменить на согласованный текстовый маркер, а после чтения XML восстановить обратно.
// Перед помещением строки в XML
СтрокаДляXML = СтрЗаменить(
ИсходнаяСтрока,
Символ(29),
"[GS]"
);
// После получения строки из XML
ВосстановленнаяСтрока = СтрЗаменить(
СтрокаИзXML,
"[GS]",
Символ(29)
);
Маркер должен быть согласован обеими сторонами обмена и не должен естественным образом встречаться в исходных данных. Если такое условие нельзя гарантировать, безопаснее использовать Base64.
Base64 подходит для передачи строк, содержащих управляющие символы, бинарные данные или сложные штрихкоды. После кодирования исходное значение представляется только допустимыми текстовыми символами и может безопасно находиться внутри XML.
На передающей стороне строка преобразуется в двоичные данные, а затем кодируется в Base64:
Функция КодироватьСтрокуВBase64(Знач ИсходнаяСтрока) Экспорт
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(
ИсходнаяСтрока
);
Возврат Base64Строка(ДвоичныеДанные);
КонецФункции
На принимающей стороне выполняется обратное преобразование:
Функция ДекодироватьСтрокуИзBase64(Знач СтрокаBase64) Экспорт
ДвоичныеДанные = Base64Значение(СтрокаBase64);
Возврат ПолучитьСтрокуИзДвоичныхДанных(
ДвоичныеДанные
);
КонецФункции
Использование выглядит следующим образом:
// Передача
КодGS1Base64 = КодироватьСтрокуВBase64(КодGS1);
// Получение
ИсходныйКодGS1 = ДекодироватьСтрокуИзBase64(
КодGS1Base64
);
Этот вариант сохраняет исходные данные без потерь, включая символ U+001D. При этом отправитель и получатель должны заранее договориться, что содержимое соответствующего элемента XML передается в Base64.
Секция CDATA позволяет помещать в XML текст, который не должен интерпретироваться как разметка. Внутри нее не требуется экранировать символы < и &.
<Документ>
<Описание>
<![CDATA[
Этот текст может содержать символы <, > и &,
а также фрагменты HTML или XML-разметки.
]]>
</Описание>
</Документ>
Однако CDATA не отменяет общие ограничения XML 1.0. Символы U+0000, U+001D и другие запрещенные управляющие символы нельзя помещать внутрь CDATA. Кроме того, внутри одной секции CDATA нельзя использовать последовательность ]]>, поскольку она завершает секцию.
Таким образом, CDATA решает проблему интерпретации символов как разметки, но не решает проблему недопустимых управляющих символов.
Если сообщение об ошибке содержит только позицию символа, можно получить символ и его числовой код средствами встроенного языка 1С.
ПозицияОшибки = 25;
ПроблемныйСимвол = Сред(
ИсходнаяСтрока,
ПозицияОшибки,
1
);
КодПроблемногоСимвола = КодСимвола(
ПроблемныйСимвол
);
Сообщить(
"Код проблемного символа: "
+ Строка(КодПроблемногоСимвола)
);
Если получено значение 29, значит, в строке находится разделитель GS. После этого можно определить, следует ли удалить его, заменить на маркер или закодировать всю строку в Base64.
ЗаписьXML, XDTO или другие штатные средства платформы. не делает символ U+001D допустимым в XML 1.0.ЗаменитьНедопустимыеСимволыXML и УдалитьНедопустимыеСимволыXML.Итак, ошибка «Текст XML содержит недопустимый символ в позиции...» возникает не из-за кодировки файла как таковой, а из-за наличия в строке символа, запрещенного спецификацией XML. Допустимые служебные символы следует передавать через штатные механизмы XML, а недопустимые управляющие символы необходимо удалить, заменить на согласованный маркер или передать в Base64. Такой подход обеспечивает корректный и устойчивый обмен данными между 1С и внешними системами.