Как исправить ошибку разбора XML: «Space required after the Public Identifier» в 1С?

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

При интеграции 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-страницу. Это может быть:

  1. Страница с ошибкой доступа (403 Forbidden).
  2. Страница «Ничего не найдено» (404 Not Found).
  3. Уведомление о перенаправлении (301 Moved Permanently или 302 Found).

Когда мы используем метод ЧтениеXML.ОткрытьФайл(URL), объект 1С пытается прочитать содержимое по ссылке. Если сервер вместо файла отдает HTML-текст вида <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">, парсер 1С, настроенный на строгий стандарт XML, выдает фатальную ошибку, так как структура HTML не соответствует правилам XML.

Шаг 1: Правильное использование HTTPСоединения и HTTPS

Рассмотрим ситуацию, когда файл находится на защищенном сервере (HTTPS). Обычное открытие файла по ссылке может не сработать. Проанализируем правильный подход с использованием объекта HTTPСоединение. Нам необходимо явно указать использование защищенного соединения.

Посмотрим на пример кода, который позволяет корректно инициализировать соединение:


// Определяем параметры сервера
Сервер = "export.hyundai-direct.biz";
Порт = 443; // Стандартный порт для HTTPS
Защита = Новый ЗащищенноеСоединениеOpenSSL();

// Создаем соединение
Соединение = Новый HTTPСоединение(Сервер, Порт, , , , , Защита);

// Формируем запрос
ПутьКФайлу = "/yml_get/tbky2fcth2pg";
Запрос = Новый HTTPЗапрос(ПутьКФайлу);

// Получаем результат
Результат = Соединение.Получить(Запрос);

В данном примере использование ЗащищенноеСоединениеOpenSSL критически важно. Без него попытка обращения к HTTPS-ресурсу завершится ошибкой сети или пустым ответом. Понимание этих принципов также необходимо, если вы реализуете выполнение запросов 1С через REST API с использованием защищенных протоколов.

Шаг 2: Обработка редиректов (перенаправлений)

Часто веб-серверы настроены так, что одна ссылка перенаправляет на другую (например, с короткого адреса на полный или с HTTP на HTTPS). Объект HTTPСоединение в 1С не умеет автоматически переходить по редиректам. Если сервер вернул код состояния 301 или 302, тело ответа будет содержать HTML-код с текстом «Document moved», который и вызывает ошибку разбора XML.

Разберем по шагам, как обработать редирект вручную:

  1. Отправляем запрос к серверу.
  2. Проверяем Результат.КодСостояния.
  3. Если код равен 301 или 302, ищем в заголовках ответа параметр Location.
  4. Создаем новый запрос по адресу из Location.

Проанализируем пример функции для получения контента с учетом одного редиректа:


Функция ПолучитьДанныеСРекурсией(Знач ТекущийURL)
    // Разбор URL на части (сервер, путь) — можно использовать вспомогательные функции
    СтруктураURL = ПолучитьСтруктуруURL(ТекущийURL); 
    
    Соединение = Новый HTTPСоединение(СтруктураURL.Сервер, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
    Запрос = Новый HTTPЗапрос(СтруктураURL.Путь);
    Результат = Соединение.Получить(Запрос);
    
    Если Результат.КодСостояния = 301 Или Результат.КодСостояния = 302 Тогда
        НовыйАдрес = Результат.Заголовки.Получить("Location");
        Возврат ПолучитьДанныеСРекурсией(НовыйАдрес); // Переходим по новой ссылке
    ИначеЕсли Результат.КодСостояния = 200 Тогда
        Возврат Результат.ПолучитьТелоКакСтроку();
    КонецЕсли;
    
    Возврат Неопределено;
КонецФункции

Шаг 3: Предварительная обработка данных

После того как мы получили строку с данными, не спешите сразу скармливать её в ФабрикаXDTO. В файлах формата YML (Yandex Market Language) часто встречаются ошибки: неэкранированные символы амперсанда (& вместо &amp;), лишние пробелы в начале файла или некорректные кодировки.

Рассмотрим алгоритм «очистки» полученной строки перед разбором:

  1. Проверяем наличие BOM (Byte Order Mark) в начале строки и удаляем его.
  2. Убеждаемся, что строка начинается с <?xml. Если перед этим тегом есть HTML-мусор или пробелы, их нужно обрезать.
  3. Используем метод УстановитьСтроку() объекта ЧтениеXML вместо открытия файла.

Пример кода загрузки из строки:


ПолученнаяСтрока = Результат.ПолучитьТелоКакСтроку();

// Убираем возможные пробелы в начале
ПолученнаяСтрока = СокрЛП(ПолученнаяСтрока);

ЧтениеXML = Новый ЧтениеXML;
Попытка
    ЧтениеXML.УстановитьСтроку(ПолученнаяСтрока);
    ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
Исключение
    Сообщить("Ошибка парсинга: " + ОписаниеОшибки());
КонецПопытки;

Шаг 4: Использование механизмов БСП

Если ваша конфигурация построена на базе БСП (Библиотеки Стандартных Подсистем) — здесь вам может пригодиться справочник по методам БСП — например, БП 3.0, УТ 11 или ERP, рассмотрите использование встроенного модуля ПолучениеФайловИзИнтернета. Процедуры этого модуля уже содержат встроенную логику обработки редиректов, работы с прокси-серверами и защищенными соединениями.

Рассмотрим вызов стандартного метода:


ПараметрыЗагрузки = ПолучениеФайловИзИнтернета.ПараметрыСкачиванияФайла();
ПараметрыЗагрузки.ИмяФайлаДляСохранения = ПолучитьИмяВременногоФайла("xml");

РезультатЗагрузки = ПолучениеФайловИзИнтернета.СкачатьФайл(URL, ПараметрыЗагрузки);

Если РезультатЗагрузки.Статус Тогда
    // Работаем с файлом
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.ОткрытьФайл(ПараметрыЗагрузки.ИмяФайлаДляСохранения);
    // ... дальнейшая логика XDTO
КонецЕсли;

Резюмируем: основная причина ошибки «Space required after the Public Identifier» — это попытка прочитать HTML-страницу редиректа как XML-документ. Используйте HTTPСоединение с SSL, проверяйте коды состояния ответов сервера и всегда анализируйте содержимое строки перед парсингом. Это сделает вашу интеграцию надежной и устойчивой к изменениям на стороне поставщиков данных.

← На главную