Почему в XML-тексте возникают недопустимые символы и как их корректно обработать в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Комплексная автоматизация Управленческий учет Торговля и дистрибуция
← К списку

При работе с обменом данными, особенно через XML, мы часто сталкиваемся с ошибкой вида "Текст XML содержит недопустимый символ в позиции...". Эта проблема может поставить в тупик, ведь иногда кажется, что мы передаем "чистые" данные. Давайте вместе разберемся, почему возникает такая ошибка и какие эффективные методы ее решения существуют в 1С и за ее пределами.

Выясним причину: эта ошибка возникает, когда в формируемом XML-документе присутствуют символы, которые не соответствуют строгой спецификации XML. Это чаще всего происходит с управляющими символами (Control Characters) из таблицы ASCII, которые не предназначены для отображения и имеют специальное значение в других контекстах (например, разделители). В XML 1.0 разрешены только символы табуляции ( ), перевода строки ( ) и возврата каретки ( ). Все остальные управляющие символы в диапазонах от U+0000 до U+0008, U+000B до U+000C, U+000E до U+001F считаются недопустимыми.

Одним из таких частых "виновников" является символ char(29) (Group Separator, GS, U+001D), который был упомянут в обсуждении. Он часто используется в штрихкодах GS1 для разделения элементов данных, но при попадании напрямую в XML вызывает ошибку. Помимо управляющих символов, существуют также зарезервированные символы (<, >, &, ', "), которые имеют специальное значение в синтаксисе XML и требуют экранирования.

Давайте рассмотрим подробнее несколько подходов к решению этой проблемы, которые мы можем применить в наших решениях на базе 1С.

1. Экранирование недопустимых символов

Один из наиболее прямых способов борьбы с недопустимыми символами — это их экранирование. Экранирование означает замену проблемного символа на его эквивалентное представление, которое XML-парсер сможет корректно обработать. Это похоже на то, как база данных MS SQL экранирует char(29) в виде "".

Разберем по шагам:

  1. Определяем проблемные символы: Выясняем, какие именно символы вызывают ошибку. Как мы уже говорили, это могут быть управляющие символы или зарезервированные символы XML.
  2. Выполняем замену: Заменяем эти символы на их соответствующие XML-сущности. Для управляющих символов используется числовая ссылка на символ: &#nnnn; (десятичный код) или &#xhhhh; (шестнадцатеричный код). Например, для char(29) это будет . Для зарезервированных символов XML используются предопределенные сущности:
    • < для <
    • > для >
    • & для &
    • ' для ' (в атрибутах)
    • " для " (в атрибутах)

В 1С мы можем использовать функцию СтрЗаменить() для замены конкретных символов. Например, если мы знаем, что проблема в Символ(29):


ПередаваемаяСтрока = СтрЗаменить(ИсходнаяСтрока, Символ(29), "");

Для более комплексной очистки данных в 1С существуют функции в "Библиотеке стандартных подсистем" (БСП), такие как ЗаменитьНедопустимыеСимволыXML и УдалитьНедопустимыеСимволыXML. Эти функции могут помочь автоматически найти и обработать проблемные символы в строке перед ее записью в XML.

2. Кодирование данных в Base64

Этот подход является очень мощным и универсальным решением, особенно когда данные содержат много "проблемных" символов или являются бинарными по своей сути. Идея заключается в том, чтобы закодировать всю строку, содержащую недопустимые символы, в формат Base64 перед ее включением в XML. На принимающей стороне эти данные затем декодируются обратно.

Проанализируем ситуацию: строка Base64 состоит исключительно из допустимых символов ASCII (буквы латинского алфавита, цифры и несколько специальных символов), что гарантирует ее беспроблемное включение в любой XML-документ. XML-парсер не столкнется с недопустимыми символами, потому что все содержимое будет восприниматься как обычный текст.

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

Для кодирования нам понадобятся функции ПолучитьДвоичныеДанныеИзСтроки() и Base64Строка(). Первая преобразует строку в двоичные данные, а вторая кодирует эти двоичные данные в строку Base64.


// Функция для кодирования строки в Base64
Функция ПреобразоватьКод_GS1(Знач СтрШК) Экспорт
    // Сначала получаем двоичные данные из исходной строки
    ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(СтрШК);
    // Затем кодируем двоичные данные в строку Base64
    Возврат Base64Строка(ДвоичныеДанные);
КонецФункции // ПреобразоватьКод_GS1()

На принимающей стороне для восстановления исходной строки мы используем обратные функции: Base64Значение() для декодирования строки Base64 в двоичные данные и ПолучитьСтрокуИзДвоичныхДанных() для преобразования двоичных данных обратно в строку.


// Функция для декодирования строки Base64 обратно в исходную строку
Функция ВосстановитьКод_GS1(Знач СтрШК_Base64) Экспорт
    // Декодируем строку Base64 в двоичные данные
    ДвоичныеДанные = Base64Значение(СтрШК_Base64);
    // Преобразуем двоичные данные обратно в строку
    Возврат ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные);
КонецФункции // ВосстановитьКод_GS1()

Таким образом, перед передачей данных с клиента на сервер или при формировании XML-файла мы вызываем ПреобразоватьКод_GS1(), а после получения данных и их извлечения из XML — ВосстановитьКод_GS1().

3. Использование секций CDATA

Секции CDATA (Character Data) предоставляют еще один способ включения текста, который XML-парсер не должен обрабатывать как разметку XML. Весь текст внутри секции воспринимается как обычные символьные данные, и в нем не нужно экранировать зарезервированные символы (например, <, >, &).

Рассмотрим подробнее: это особенно полезно, когда ваш текст содержит много специальных символов или даже фрагменты, которые выглядят как XML-разметка, но не должны интерпретироваться как таковые. Например, если вы передаете фрагмент HTML или XML как данные внутри другого XML-документа.

Пример использования:


<Документ>
    <Описание>
        , &,
            а также управляющие символы, которые будут проигнорированы парсером.
            Например, Символ(29) здесь не вызовет ошибку,
            но и не будет интерпретирован как разметка.
        ]]>
    

Важный момент: хотя секции CDATA избавляют от необходимости экранировать зарезервированные символы, они не решают проблему с управляющими символами (такими как char(29)) в XML 1.0. Большинство XML-парсеров все равно выдадут ошибку, если внутри секции CDATA обнаружится недопустимый управляющий символ. Поэтому для управляющих символов лучше использовать экранирование (&#xHHHH;) или кодирование в Base64.

Лучшие практики и дополнительные рекомендации

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

  1. Проверка и очистка входных данных: Крайне важно выполнять строгую проверку и очистку всех входных данных перед их включением в XML-документ. Это помогает предотвратить появление недопустимых символов и потенциальные уязвимости.
  2. Использование XML-библиотек: При создании или изменении XML-документов всегда рекомендуется использовать специализированные XML-библиотеки и инструменты. Они автоматически обрабатывают экранирование зарезервированных символов, что снижает вероятность ошибок. В 1С это, например, объекты ЗаписьXML и ЧтениеXML, которые корректно обрабатывают многие аспекты формирования и парсинга XML.
  3. Функции 1С для работы с XML: Как уже упоминалось, в "Библиотеке стандартных подсистем" (БСП) есть встроенные функции, такие как ЗаменитьНедопустимыеСимволыXML и УдалитьНедопустимыеСимволыXML, которые могут быть полезны для предварительной очистки строк, особенно если данные поступают из внешних источников (например, скопированы из интернета или из текстовых файлов).

Применяя эти методы, мы сможем эффективно бороться с ошибками "Текст XML содержит недопустимый символ в позиции..." и обеспечивать надежный обмен данными в наших решениях на платформе 1С.

← К списку