При интеграции 1С с внешними системами, например, когда необходима выгрузка и загрузка данных XML или загрузка данных товаров из файлов формата YML, программисты часто сталкиваются с загадочной ошибкой: «Ошибка разбора XML: - [1,50] Фатальная ошибка: Space required after the Public Identifier». Ситуация осложняется тем, что часть файлов может обрабатываться корректно, а часть — вызывать исключение. В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем механизм работы веб-серверов и научимся правильно загружать данные в 1С.
Давайте проанализируем текст ошибки. Координаты [1,50] указывают на то, что парсер нашел некорректный символ в первой строке в районе 50-й позиции. Сообщение Space required after the Public Identifier специфично для обработки заголовка DOCTYPE.
Важный момент: если вы ожидаете XML, а парсер ругается на DOCTYPE, это в 99% случаев означает, что вместо XML-данных сервер прислал вам обычную HTML-страницу. Это может быть:
Когда мы используем метод ЧтениеXML.ОткрытьФайл(URL), объект 1С пытается прочитать содержимое по ссылке. Если сервер вместо файла отдает HTML-текст вида <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">, парсер 1С, настроенный на строгий стандарт XML, выдает фатальную ошибку, так как структура HTML не соответствует правилам XML.
Рассмотрим ситуацию, когда файл находится на защищенном сервере (HTTPS). Обычное открытие файла по ссылке может не сработать. Проанализируем правильный подход с использованием объекта HTTPСоединение. Нам необходимо явно указать использование защищенного соединения.
Посмотрим на пример кода, который позволяет корректно инициализировать соединение:
// Определяем параметры сервера
Сервер = "export.hyundai-direct.biz";
Порт = 443; // Стандартный порт для HTTPS
Защита = Новый ЗащищенноеСоединениеOpenSSL();
// Создаем соединение
Соединение = Новый HTTPСоединение(Сервер, Порт, , , , , Защита);
// Формируем запрос
ПутьКФайлу = "/yml_get/tbky2fcth2pg";
Запрос = Новый HTTPЗапрос(ПутьКФайлу);
// Получаем результат
Результат = Соединение.Получить(Запрос);
В данном примере использование ЗащищенноеСоединениеOpenSSL критически важно. Без него попытка обращения к HTTPS-ресурсу завершится ошибкой сети или пустым ответом. Понимание этих принципов также необходимо, если вы реализуете выполнение запросов 1С через REST API с использованием защищенных протоколов.
Часто веб-серверы настроены так, что одна ссылка перенаправляет на другую (например, с короткого адреса на полный или с HTTP на HTTPS). Объект HTTPСоединение в 1С не умеет автоматически переходить по редиректам. Если сервер вернул код состояния 301 или 302, тело ответа будет содержать HTML-код с текстом «Document moved», который и вызывает ошибку разбора XML.
Разберем по шагам, как обработать редирект вручную:
Результат.КодСостояния.Location.Location.Проанализируем пример функции для получения контента с учетом одного редиректа:
Функция ПолучитьДанныеСРекурсией(Знач ТекущийURL)
// Разбор URL на части (сервер, путь) — можно использовать вспомогательные функции
СтруктураURL = ПолучитьСтруктуруURL(ТекущийURL);
Соединение = Новый HTTPСоединение(СтруктураURL.Сервер, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
Запрос = Новый HTTPЗапрос(СтруктураURL.Путь);
Результат = Соединение.Получить(Запрос);
Если Результат.КодСостояния = 301 Или Результат.КодСостояния = 302 Тогда
НовыйАдрес = Результат.Заголовки.Получить("Location");
Возврат ПолучитьДанныеСРекурсией(НовыйАдрес); // Переходим по новой ссылке
ИначеЕсли Результат.КодСостояния = 200 Тогда
Возврат Результат.ПолучитьТелоКакСтроку();
КонецЕсли;
Возврат Неопределено;
КонецФункции
После того как мы получили строку с данными, не спешите сразу скармливать её в ФабрикаXDTO. В файлах формата YML (Yandex Market Language) часто встречаются ошибки: неэкранированные символы амперсанда (& вместо &), лишние пробелы в начале файла или некорректные кодировки.
Рассмотрим алгоритм «очистки» полученной строки перед разбором:
<?xml. Если перед этим тегом есть HTML-мусор или пробелы, их нужно обрезать.УстановитьСтроку() объекта ЧтениеXML вместо открытия файла.Пример кода загрузки из строки:
ПолученнаяСтрока = Результат.ПолучитьТелоКакСтроку();
// Убираем возможные пробелы в начале
ПолученнаяСтрока = СокрЛП(ПолученнаяСтрока);
ЧтениеXML = Новый ЧтениеXML;
Попытка
ЧтениеXML.УстановитьСтроку(ПолученнаяСтрока);
ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
Исключение
Сообщить("Ошибка парсинга: " + ОписаниеОшибки());
КонецПопытки;
Если ваша конфигурация построена на базе БСП (Библиотеки Стандартных Подсистем) — здесь вам может пригодиться справочник по методам БСП — например, БП 3.0, УТ 11 или ERP, рассмотрите использование встроенного модуля ПолучениеФайловИзИнтернета. Процедуры этого модуля уже содержат встроенную логику обработки редиректов, работы с прокси-серверами и защищенными соединениями.
Рассмотрим вызов стандартного метода:
ПараметрыЗагрузки = ПолучениеФайловИзИнтернета.ПараметрыСкачиванияФайла();
ПараметрыЗагрузки.ИмяФайлаДляСохранения = ПолучитьИмяВременногоФайла("xml");
РезультатЗагрузки = ПолучениеФайловИзИнтернета.СкачатьФайл(URL, ПараметрыЗагрузки);
Если РезультатЗагрузки.Статус Тогда
// Работаем с файлом
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПараметрыЗагрузки.ИмяФайлаДляСохранения);
// ... дальнейшая логика XDTO
КонецЕсли;
Резюмируем: основная причина ошибки «Space required after the Public Identifier» — это попытка прочитать HTML-страницу редиректа как XML-документ. Используйте HTTPСоединение с SSL, проверяйте коды состояния ответов сервера и всегда анализируйте содержимое строки перед парсингом. Это сделает вашу интеграцию надежной и устойчивой к изменениям на стороне поставщиков данных.