Как исправить ошибку «Char 0x0 out of allowed range» при чтении XML на мобильной платформе 1С?

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

Разработка под мобильную платформу 1С часто преподносит сюрпризы, которые не проявляются в обычном тонком или толстом клиенте. Одной из таких проблем является ошибка «Char 0x0 out of allowed range» при выполнении метода ПрочитатьXML() или использовании ФабрикаXDTO. В этой статье мы подробно разберем, почему возникает эта ошибка, чем мобильная платформа отличается от десктопной в плане парсинга данных, и рассмотрим несколько эффективных способов решения проблемы.

Выясняем причину возникновения ошибки

Проанализируем ситуацию: ошибка сообщает нам о наличии символа с кодом 0x0 (так называемый null-terminator) в теле XML-документа. Согласно спецификации XML, данный символ является недопустимым. Однако возникает вопрос: почему один и тот же код работает в мобильном клиенте, но «валится» в автономном мобильном приложении?

Разберем этот механизм. Когда мы используем мобильный клиент, основной код выполняется на стороне сервера (под управлением Windows или Linux), где библиотеки парсинга (например, встроенные в ОС) могут игнорировать завершающий нулевой байт. В мобильном же приложении код выполняется локально на устройстве (Android или iOS). Мобильный движок 1С использует системные библиотеки парсинга (такие как libxml2), которые крайне строго следуют стандартам. Если в поток данных попадает хотя бы один лишний байт 0x0 (который часто добавляется веб-серверами или при передаче бинарных данных как текста), парсер немедленно прерывает работу с ошибкой.

Способ №1: Принудительная очистка строки (Рекомендуемый)

Самый простой и производительный способ — это программное удаление недопустимых символов из полученного текста перед тем, как передать его в объект ЧтениеXML. Если вы получаете данные от HTTP-сервера в виде строки, воспользуемся методом СтрЗаменить.

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


// Предположим, что в переменной "ДанныеОтСервера" находится текст XML
ТекстБезМусора = СтрЗаменить(ДанныеОтСервера, Символ(0), "");

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстБезМусора);

// Выполняем чтение через Фабрику XDTO
Инвент = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();

Этот метод хорош тем, что он не требует обращения к файловой системе устройства, что положительно сказывается на скорости работы приложения, особенно при обработке больших объемов данных.

Способ №2: Использование временного файла

Если данные приходят в специфической кодировке или метод УстановитьСтроку продолжает выдавать ошибку, можно прибегнуть к промежуточному сохранению во временный файл. Как показывает практика, при записи текста в файл и его последующем открытии через ОткрытьФайл, платформа 1С более корректно обрабатывает буферы памяти.

Посмотрим на алгоритм, который помог автору темы:


// Создаем уникальное имя временного файла
ИмяФайла = ПолучитьИмяВременногоФайла("xml");

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

// Читаем XML уже из файла
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);

Инвент = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();

// Не забываем удалять временный файл
УдалитьФайлы(ИмяФайла);

Обратите внимание, что использование КодировкаТекста.ANSI или UTF-8 должно соответствовать реальной кодировке данных, приходящих с сервера.

Способ №3: Правильная работа с потоками и ДвоичнымиДанными

Часто ошибка 0x0 возникает из-за некорректного определения длины контента сервером (заголовок Content-Length). Если сервер передает на один байт больше, чем нужно, этот «нулевой» байт попадает в конец потока. Вместо прямой установки строки попробуем использовать объект ДвоичныеДанные, который позволяет более гибко управлять содержимым.

Проанализируем следующий подход:

  1. Получаем тело ответа от сервера как ДвоичныеДанные.
  2. Преобразуем их в строку, явно указывая кодировку и игнорируя возможные ошибки в конце буфера.
  3. Передаем «чистую» строку в парсер.

// Получаем ответ от HTTP-запроса
ТелоДвоичныеДанные = HTTPОтвет.ПолучитьТелоКакДвоичныеДанные();

// Преобразуем в строку (например, UTF-8)
// Метод ПолучитьСтрокуИзДвоичныхДанных корректно обрабатывает содержимое
ТекстXML = ПолучитьСтрокуИзДвоичныхДанных(ТелоДвоичныеДанные, КодировкаТекста.UTF8);

// Дополнительно страхуемся от null-terminator
ТекстXML = СтрЗаменить(ТекстXML, Символ(0), "");

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстXML);
// Далее чтение через Фабрику...

Важные нюансы мобильной платформы 8.3.22

Стоит отметить, что в версиях платформы ветки 8.3.22 (включая сборку 57) были замечены особенности работы с методом ОткрытьПоток(). В некоторых случаях этот метод может приводить к нестабильной работе или утечкам памяти в мобильном приложении. Поэтому, если вы столкнулись с ошибкой «Char 0x0 out of allowed range», использование УстановитьСтроку() с предварительной очисткой (как в способе №1) считается наиболее надежным вариантом.

Также проверьте наличие BOM (Byte Order Mark). Это невидимые символы в начале файла EF BB BF для UTF-8. Если сервер присылает их, ЧтениеXML на мобильном устройстве может воспринять их как некорректный символ. Очистка строки через СтрЗаменить или использование метода ПолучитьТелоКакСтроку() у объекта HTTPОтвет обычно решают эту проблему автоматически, так как платформа сама отсекает BOM при получении строки.

Резюме для разработчика

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

← На главную