Как исправить ошибку разбора XML при загрузке HTML-страницы через HTTP в 1С?

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

При выполнении HTTP-запросов к внешним ресурсам разработчики нередко сталкиваются с ситуацией, когда метод ЧтениеXML.Прочитать() завершается фатальной ошибкой вида: «Ошибка разбора XML: Opening and ending tag mismatch». Проанализируем, почему возникает эта проблема и как правильно обработать входящие данные HTML-формата в 1С.

Выясним причину ошибки: отличие стандартов HTML и XML

Рассмотрим причину падения XML-парсера. Документы XML требуют строгого соответствия синтаксису: каждый открывающий тег обязательно должен закрываться парным тегом или быть самозакрывающимся (например, <link />). В то же время HTML5 допускает использование одиночных тегов без явного закрытия — таких как <meta>, <link>, <img>, <br>.

Если сервер в ответ на HTTP-запрос возвращает не XML, а обычную HTML-страницу (что видно по строке <!DOCTYPE html> в начале ответа), объект ЧтениеXML спотыкается на первом же незакрытом теге (например, <meta charset='utf-8'>) и прекращает работу.

Решение проблемы с помощью объектов ЧтениеHTML, ПостроительDOM и ОбходДереваDOM

Для корректного разбора HTML-документа необходимо использовать специализированные объекты платформы 1С. Разберем рабочую последовательность действий.

При попытке применить объект ИтераторУзловDOM в некоторых релизах платформы возможен сбой приложения. Чтобы избежать аварийного завершения работы 1С, используем объект ОбходДереваDOM.

Рассмотрим по шагам пример кода для чтения HTML-файла и обхода его узлов:


ИмяВыходногоФайла = "C:\temp\response.html";

// 1. Инициализируем объект чтения HTML
ЧтениеHTML = Новый ЧтениеHTML;
ЧтениеHTML.ОткрытьФайл(ИмяВыходногоФайла, "UTF-8");

// 2. Строим дерево DOM
ПостроительDOM = Новый ПостроительDOM;
ДокументHTML = ПостроительDOM.Прочитать(ЧтениеHTML);

// 3. Создаем объект обхода дерева DOM вместо ИтератораУзлов
Обход = Новый ОбходДереваDOM(ДокументHTML);
ТекущийУзел = Обход.ПервыйДочерний();

Пока ТекущийУзел <> Неопределено Цикл
    Если ТекущийУзел.ИмяУзла = "a" Тогда
        // Обработка ссылок или нужных элементов
        Сообщить("Найдена ссылка: " + ТекущийУзел.ТекстовоеСодержимое);
    КонецЕсли;
    ТекущийУзел = Обход.СледующийСоседний();
КонецЦикла;

ЧтениеHTML.Закрыть();

Альтернативный способ: использование объекта ФорматированныйДокумент

Если задача заключается в том, чтобы быстро извлечь текстовое содержимое или структуры списков из полученной HTML-страницы без сложной навигации по узлам DOM, можно воспользоваться объектом ФорматированныйДокумент.

Проанализируем пример выполнения HTTP-запроса и загрузки ответа в 1С:


Сервер = "мояколея1520.рф";
Соединение = Новый HTTPСоединение(Сервер);
ЗапросHTTP = Новый HTTPЗапрос("/wagon/search");

Ответ = Соединение.ВызватьHTTPМетод("POST", ЗапросHTTP);
ТелоКакСтрока = Ответ.ПолучитьТелоКакСтроку();

ФорматированныйДокумент = Новый ФорматированныйДокумент;
ФорматированныйДокумент.УстановитьHTML(ТелоКакСтрока, Новый Структура);

Для Каждого Элемент Из ФорматированныйДокумент.Элементы Цикл
    Если ТипЗнч(Элемент) = Тип("ПараграфФорматированногоДокумента") Тогда
        Если СокрЛП(Элемент.ТипПараграфа) = "Нумерованный список" Тогда
            Для Каждого ЭлементСписка Из Элемент.Элементы Цикл
                Сообщить(ЭлементСписка.Текст);
            КонецЦикла;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Проверка ответа HTTP и предотвращение ошибок

Чтобы убедиться, что от веб-сервера пришел именно тот формат данных, который ожидается, соблюдаем следующие правила при работе с HTTP-запросами:

  1. Проверяем код состояния HTTP-ответа: Перед вызовом методов чтения убеждаемся, что Ответ.КодСостояния равен 200. При кодах 404 или 500 сервер отдаст HTML-страницу с описанием ошибки.
  2. Проверяем заголовок Content-Type: Из коллекции Ответ.Заголовки извлекаем значение Content-Type. Если в нем содержится text/html, применять ЧтениеXML нельзя.
  3. Передаем правильные заголовки HTTPЗапрос: Чтобы сервер вернул XML или JSON вместо HTML-страницы, явно задаем заголовок Accept, например: ЗапросHTTP.Заголовки.Вставить("Accept", "application/xml").
← На главную