Допустимая ошибка при разборе HTML / XML / SGML в PHP - PullRequest
5 голосов
/ 16 сентября 2008

У меня есть несколько устаревших документов, похожих на HTML. Например, они выглядят как HTML, но имеют дополнительные составные теги, которые не являются частью HTML

<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>

Мне нужно разобрать эти файлы. PHP - единственный доступный инструмент. Документы не приближаются к тому, чтобы быть правильно сформированным XML.

Моя первоначальная мысль заключалась в том, чтобы использовать методы loadHTML в PHP DOMDocument. Тем не менее, эти методы подавляют макияж HTML-тэги и отказываются анализировать строку / файл.

$oDom = new DomDocument();
$oDom->loadHTML("<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>");
//gives us
DOMDocument::loadHTML() [function.loadHTML]: Tag pseud-template invalid in Entity, line: 1 occured in ....

Единственное решение, которое мне удалось найти, - это предварительно обработать файлы с помощью функции замены строк, которая удалит недопустимые теги и заменит их допустимым тегом HTML (возможно, span с идентификатором тега имя).

Есть ли более элегантное решение? Способ сообщить DOMDocument о дополнительных тегах, которые следует считать действительными? Существует ли другой надежный класс / объект для анализа HTML для PHP?

(если это не очевидно, я не считаю правильные решения здесь регулярными выражениями)

Обновление : информация в поддельных тегах является частью цели, поэтому что-то вроде Tidy не вариант. Кроме того, я стремлюсь к чему-то, что делает некоторый уровень, если не весь, очистки правильной формы для меня, поэтому я в первую очередь искал метод loadHTML DomDocument.

Ответы [ 6 ]

6 голосов
/ 01 сентября 2010

Вы можете подавить предупреждения с помощью libxml_use_internal_errors при загрузке документа. Eg.:

libxml_use_internal_errors(true);
$doc = new DomDocument();
$doc->loadHTML("<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>");
libxml_use_internal_errors(false);

Если по какой-то причине вам необходим доступ к предупреждениям, используйте libxml_get_errors

2 голосов
/ 16 сентября 2008

Интересно, может ли пропустить «плохой» HTML через HTML Tidy в качестве первого прохода? Возможно, стоит взглянуть, если вы можете сделать документ правильно сформированным, возможно, вы можете загрузить его как обычный XML-файл с DomDocument.

1 голос
/ 16 сентября 2008

Посмотрите на Parser в порте PHP Fit. Код чистый и изначально предназначен для загрузки грязного HTML, сохраненного в Word. Он настроен на извлечение таблиц, но его легко адаптировать.

Вы можете увидеть источник здесь: http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/Parser.phps

Модульный тест покажет вам, как его использовать: http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/test/parser.phps

1 голос
/ 16 сентября 2008

@ Twan Вам не нужно DTD для DOMDocument для анализа пользовательского XML. Просто используйте DOMDocument->load(), и пока XML правильно сформирован, он может читать его.

Как только вы сделаете файлы правильно сформированными, тогда вы сможете начать анализировать XML-парсеры, прежде чем стать S.O.L. Лок Алехо сказал, что вы можете посмотреть на HTML TIDY , но похоже, что это специфично для HTML, и я не знаю, как это будет с вашими пользовательскими элементами.

Я не считаю регулярные выражения правильным решением здесь

Пока у вас нет правильной формы, это может быть вашим единственным вариантом. Как только вы получите документы на этом этапе, вы будете в курсе функций DOM.

0 голосов
/ 16 сентября 2008

@ Alan Storm

Ваш комментарий к моему другому ответу заставил меня задуматься:

Когда вы загружаете HTML-файл с помощью DOMDocument, он, кажется, выполняет определенный уровень очистки: хорошая корректность, НО требует, чтобы все ваши теги были допустимыми тегами HTML. Я ищу то, что делает первое, но не позднее. (Алан Сторм)

Запустите регулярное выражение (извините!) Над тегами, и, когда оно найдет элемент, который не является допустимым элементом HTML, замените его на допустимый элемент, который, как вы знаете, не существует ни в одном из документов (blink приходит на ум ...) и присваивает ему значение атрибута с именем недопустимого элемента, чтобы потом можно было переключить его обратно. например:

$code = str_replace("<pseudo-tag>", "<blink rel=\"pseudo-tag\">", $code);
// and then back again...
$code = preg_replace('<blink rel="(.*?)">', '<\1>', $code);

очевидно, что код не будет работать, но у вас есть общее представление?

0 голосов
/ 16 сентября 2008

Моим быстрым и грязным решением этой проблемы было запустить цикл, который сопоставляет мой список пользовательских тегов с регулярным выражением. Регулярное выражение не перехватывает теги, в которых есть другой внутренний тег.

При совпадении вызывается функция для обработки этого тега и возвращает «обработанный HTML». Если этот пользовательский тег был внутри другого пользовательского тега, родительский элемент становится бездетным из-за того, что фактический HTML был вставлен вместо дочернего, и он будет сопоставлен с помощью регулярного выражения и обработан на следующей итерации цикла.

Цикл заканчивается, когда нет никаких бездетных пользовательских тегов для сопоставления. В целом это итеративно (цикл while), а не рекурсивно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...