При работе с XML-файлами в среде 1С разработчики часто сталкиваются с крайне коварной ошибкой: «Ошибка разбора XML: - [1,1] Фатальная ошибка: Document is empty» (Документ пуст). Особенную головную боль вызывает ситуация, когда на клиенте (в интерактивном режиме) код отрабатывает без нареканий, но при переносе логики на сервер (или при запуске регламентного задания) система падает с ошибкой.
Координаты [1,1] однозначно указывают на то, что парсер XML споткнулся на самом первом символе в первой строке документа. Это означает, что парсеру на вход не поступило вообще никаких данных (пришла пустая строка) либо переданные данные абсолютно не соответствуют формату XML. В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем различные сценарии работы платформы в клиент-серверном режиме и найдем надежные способы ее устранения.
Это одна из самых распространенных ошибок начинающих разработчиков 1С. Проанализируем, в чем заключается принципиальная разница между этими методами объекта ЧтениеXML:
ОткрытьФайл(ПутьКФайлу) инициализирует чтение XML-документа непосредственно из файла, сохраненного на диске. В качестве параметра он принимает строку с полным путем к файлу.УстановитьСтроку(СодержимоеXML) инициализирует чтение XML из оперативной памяти. В качестве параметра он ожидает саму XML-структуру в виде текста (строку, которая начинается с тегов вроде <?xml version="1.0" ...?>).Если в метод УстановитьСтроку() передать переменную, содержащую обычный путь к файлу на сервере (например, "C:\Temp\import.xml"), парсер попытается прочитать эту строку пути как XML-код. Естественно, он не обнаружит там корректных тегов и выдаст фатальную ошибку разбора в позиции [1,1].
Посмотрим на пример правильной работы с обоими методами:
// ВАРИАНТ 1. Чтение напрямую из файла на диске
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ПутьКФайлу);
Исключение
ЗаписьЖурналаРегистрации("Чтение XML", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось открыть файл для чтения!";
КонецПопытки;
Пока ЧтениеXML.Прочитать() Цикл
// Обрабатываем узлы XML-документа
КонецЦикла;
ЧтениеXML.Закрыть();
// ВАРИАНТ 2. Чтение из строковой переменной (например, полученной из HTTP-ответа)
ТекстXML = "<?xml version=""1.0"" encoding=""UTF-8""?><Root><Data>Значение</Data></Root>";
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(ТекстXML);
Пока ЧтениеXML.Прочитать() Цикл
// Обрабатываем узлы XML-документа
КонецЦикла;
ЧтениеXML.Закрыть();
Ситуация, когда на клиенте код работает, а на сервере выдает ошибку, часто связана со спецификой передачи параметров. На стороне клиента переменная (например, путь к файлу или строка XML) заполнена актуальными данными. Однако при вызове серверного метода значение переменной может теряться или искажаться. Для отладки таких процессов обмена и контроля файлов на диске сервера удобно использовать двухпанельный файловый менеджер для 1С.
Рассмотрим ситуацию: если на сервере переменная с путем к файлу оказывается пустой ("") или имеет значение Неопределено, вызов метода чтения неизбежно приведет к ошибке пустого документа.
Для гарантированной передачи файлов с клиента на сервер мы рекомендуем использовать временное хранилище. Разберем этот паттерн по шагам:
// На Клиенте
&НаКлиенте
Процедура ОбработатьФайлНаКлиенте()
ПутьКФайлуКлиент = "C:\MyFiles\data.xml";
// Помещаем файл во временное хранилище на клиенте
АдресХранилища = "";
ПоместитьФайл(АдресХранилища, ПутьКФайлуКлиент, , Ложь);
// Передаем адрес хранилища на сервер для обработки
ОбработатьФайлНаСервере(АдресХранилища);
КонецПроцедуры
// На Сервере
&НаСервере
Процедура ОбработатьФайлНаСервере(АдресХранилища)
// Получаем двоичные данные из хранилища
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);
// Создаем временное имя файла в каталоге сервера приложений
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
// Записываем данные на диск сервера
ДвоичныеДанные.Записать(ИмяВременногоФайла);
// Читаем файл на сервере
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.ОткрытьФайл(ИмяВременногоФайла);
Пока ЧтениеXML.Прочитать() Цикл
// Логика обработки XML
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации("Ошибка сервера при чтении XML", УровеньЖурналаРегистрации.Ошибка);
КонецПопытки;
ЧтениеXML.Закрыть();
// Не забываем удалить временный файл после обработки
УдалитьФайлы(ИмяВременногоФайла);
КонецПроцедуры
Если файл создается, записывается и сразу же читается в рамках одного процесса на сервере, операционная система может не успеть освободить дескриптор файла. В этом случае файл физически существует на диске, но при попытке чтения сервер 1С получает пустой поток (0 байт), что приводит к ошибке Document is empty.
Проанализируем основные методы борьбы с этой проблемой:
ЗаписьXML или ТекстовыйДокумент, обязательно убедитесь, что в коде явно вызван метод Закрыть(). До тех пор, пока поток записи открыт, читать файл нельзя.Файл.Посмотрим на пример реализации безопасного открытия файла с проверкой его готовности:
ПроверяемыйФайл = Новый Файл(ПутьКФайлу);
Если Не ПроверяемыйФайл.Существует() Тогда
ВызватьИсключение "Файл физически отсутствует на сервере: " + ПутьКФайлу;
КонецЕсли;
Если ПроверяемыйФайл.Размер() = 0 Тогда
// Файл пуст. Возможно, он еще записывается другим процессом
ВызватьИсключение "Файл поврежден или пуст (размер 0 байт): " + ПутьКФайлу;
КонецЕсли;
Кроме того, на стороне серверной ОС файлы в каталоге временных файлов часто блокируются антивирусным ПО (например, Kaspersky Endpoint Security). Антивирус перехватывает обращение процесса rphost.exe к новому файлу для проверки "на лету", блокируя чтение. Чтобы решить эту проблему, системному администратору необходимо добавить рабочие каталоги сервера 1С и процессы платформы в исключения антивируса.
Иногда сам XML-файл оказывается поврежденным. Если при передаче по каналам связи (например, через FTP) произошел сбой, файл может записаться не полностью. В результате он обрывается на полуслове и не содержит закрывающих тегов. Чтобы быстро выявить подобные ошибки структуры, можно использовать инструмент для проверки валидности XML-файлов.
Еще одна неочевидная проблема — наличие невидимых символов BOM (Byte Order Mark) в начале файла. Некоторые текстовые редакторы сохраняют UTF-8 файлы с этими маркерами последовательности байтов. Парсер XML на сервере 1С в определенных случаях может некорректно обрабатывать BOM, воспринимая его как недопустимый мусор перед объявлением XML-документа.
Попробуйте открыть файл в обычном браузере или текстовом редакторе (например, Notepad++ с отображением скрытых символов) под той учетной записью, под которой крутится служба сервера 1С (обычно это USR1CV8). Если файл не открывается в браузере с ошибкой форматирования, то проблему нужно решать на стороне отправителя файла.
Если код написан идеально, права доступа настроены правильно, файлы не заблокированы, но ошибка разбора XML все равно периодически возникает на сервере после очередного обновления конфигурации, дело может быть в "демоническом" (динамическом) обновлении базы 1С.
При динамическом обновлении серверный кэш метаданных часто повреждается. В результате платформа при обращении к схемам XML или веб-сервисам начинает возвращать пустые структуры. Для устранения этой проблемы выполните следующие действия:
snccntx и кэш-каталоги в каталоге srvinfo).Подводя итоги, отметим, что для стабильного разбора XML на сервере всегда необходимо строго разграничивать методы работы со строками и файлами, тщательно контролировать существование и размер файлов на диске сервера, а также использовать безопасные механизмы передачи данных через временное хранилище.