Разработка под мобильную платформу 1С часто преподносит сюрпризы, которые не проявляются в обычном тонком или толстом клиенте. Одной из таких проблем является ошибка «Char 0x0 out of allowed range» при выполнении метода ПрочитатьXML() или использовании ФабрикаXDTO. В этой статье мы подробно разберем, почему возникает эта ошибка, чем мобильная платформа отличается от десктопной в плане парсинга данных, и рассмотрим несколько эффективных способов решения проблемы.
Проанализируем ситуацию: ошибка сообщает нам о наличии символа с кодом 0x0 (так называемый null-terminator) в теле XML-документа. Согласно спецификации XML, данный символ является недопустимым. Однако возникает вопрос: почему один и тот же код работает в мобильном клиенте, но «валится» в автономном мобильном приложении?
Разберем этот механизм. Когда мы используем мобильный клиент, основной код выполняется на стороне сервера (под управлением Windows или Linux), где библиотеки парсинга (например, встроенные в ОС) могут игнорировать завершающий нулевой байт. В мобильном же приложении код выполняется локально на устройстве (Android или iOS). Мобильный движок 1С использует системные библиотеки парсинга (такие как libxml2), которые крайне строго следуют стандартам. Если в поток данных попадает хотя бы один лишний байт 0x0 (который часто добавляется веб-серверами или при передаче бинарных данных как текста), парсер немедленно прерывает работу с ошибкой.
Самый простой и производительный способ — это программное удаление недопустимых символов из полученного текста перед тем, как передать его в объект ЧтениеXML. Если вы получаете данные от HTTP-сервера в виде строки, воспользуемся методом СтрЗаменить.
Рассмотрим пример реализации:
// Предположим, что в переменной "ДанныеОтСервера" находится текст XML
ТекстБезМусора = СтрЗаменить(ДанныеОтСервера, Символ(0), "");
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстБезМусора);
// Выполняем чтение через Фабрику XDTO
Инвент = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
Этот метод хорош тем, что он не требует обращения к файловой системе устройства, что положительно сказывается на скорости работы приложения, особенно при обработке больших объемов данных.
Если данные приходят в специфической кодировке или метод УстановитьСтроку продолжает выдавать ошибку, можно прибегнуть к промежуточному сохранению во временный файл. Как показывает практика, при записи текста в файл и его последующем открытии через ОткрытьФайл, платформа 1С более корректно обрабатывает буферы памяти.
Посмотрим на алгоритм, который помог автору темы:
// Создаем уникальное имя временного файла
ИмяФайла = ПолучитьИмяВременногоФайла("xml");
// Записываем полученный поток (текст) в файл
ТекстЗапись = Новый ЗаписьТекста;
ТекстЗапись.Открыть(ИмяФайла, КодировкаТекста.ANSI); // Кодировка зависит от вашего источника
ТекстЗапись.ЗаписатьСтроку(ПотокТекста);
ТекстЗапись.Закрыть();
// Читаем XML уже из файла
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайла);
Инвент = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
ЧтениеXML.Закрыть();
// Не забываем удалять временный файл
УдалитьФайлы(ИмяФайла);
Обратите внимание, что использование КодировкаТекста.ANSI или UTF-8 должно соответствовать реальной кодировке данных, приходящих с сервера.
Часто ошибка 0x0 возникает из-за некорректного определения длины контента сервером (заголовок Content-Length). Если сервер передает на один байт больше, чем нужно, этот «нулевой» байт попадает в конец потока. Вместо прямой установки строки попробуем использовать объект ДвоичныеДанные, который позволяет более гибко управлять содержимым.
Проанализируем следующий подход:
ДвоичныеДанные.
// Получаем ответ от HTTP-запроса
ТелоДвоичныеДанные = HTTPОтвет.ПолучитьТелоКакДвоичныеДанные();
// Преобразуем в строку (например, UTF-8)
// Метод ПолучитьСтрокуИзДвоичныхДанных корректно обрабатывает содержимое
ТекстXML = ПолучитьСтрокуИзДвоичныхДанных(ТелоДвоичныеДанные, КодировкаТекста.UTF8);
// Дополнительно страхуемся от null-terminator
ТекстXML = СтрЗаменить(ТекстXML, Символ(0), "");
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстXML);
// Далее чтение через Фабрику...
Стоит отметить, что в версиях платформы ветки 8.3.22 (включая сборку 57) были замечены особенности работы с методом ОткрытьПоток(). В некоторых случаях этот метод может приводить к нестабильной работе или утечкам памяти в мобильном приложении. Поэтому, если вы столкнулись с ошибкой «Char 0x0 out of allowed range», использование УстановитьСтроку() с предварительной очисткой (как в способе №1) считается наиболее надежным вариантом.
Также проверьте наличие BOM (Byte Order Mark). Это невидимые символы в начале файла EF BB BF для UTF-8. Если сервер присылает их, ЧтениеXML на мобильном устройстве может воспринять их как некорректный символ. Очистка строки через СтрЗаменить или использование метода ПолучитьТелоКакСтроку() у объекта HTTPОтвет обычно решают эту проблему автоматически, так как платформа сама отсекает BOM при получении строки.
Для стабильной работы загрузки XML на мобильном устройстве придерживайтесь следующих правил:
Символ(0).УстановитьСтроку() вместо ОткрытьПоток() для небольших и средних XML-файлов на старых версиях мобильной платформы.ПолучитьСтрокуИзДвоичныхДанных с явным указанием кодировки.