При выполнении HTTP-запросов к внешним ресурсам разработчики нередко сталкиваются с ситуацией, когда метод ЧтениеXML.Прочитать() завершается фатальной ошибкой вида: «Ошибка разбора XML: Opening and ending tag mismatch». Проанализируем, почему возникает эта проблема и как правильно обработать входящие данные HTML-формата в 1С.
Рассмотрим причину падения XML-парсера. Документы XML требуют строгого соответствия синтаксису: каждый открывающий тег обязательно должен закрываться парным тегом или быть самозакрывающимся (например, <link />). В то же время HTML5 допускает использование одиночных тегов без явного закрытия — таких как <meta>, <link>, <img>, <br>.
Если сервер в ответ на HTTP-запрос возвращает не XML, а обычную HTML-страницу (что видно по строке <!DOCTYPE html> в начале ответа), объект ЧтениеXML спотыкается на первом же незакрытом теге (например, <meta charset='utf-8'>) и прекращает работу.
Для корректного разбора 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-запросами:
Ответ.КодСостояния равен 200. При кодах 404 или 500 сервер отдаст HTML-страницу с описанием ошибки.Ответ.Заголовки извлекаем значение Content-Type. Если в нем содержится text/html, применять ЧтениеXML нельзя.Accept, например: ЗапросHTTP.Заголовки.Вставить("Accept", "application/xml").