У меня есть куча устаревших документов, похожих на 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 не является вариантом. Кроме того, я за чем-то, что делает некоторый уровень, если не все, для корректной очистки для меня, и именно поэтому я искал метод LoadDTML DomDocument в первую очередь.
Вы можете подавлять предупреждения с помощью libxml_use_internal_errors
при загрузке документа. Например.:
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
Интересно, может ли передача «плохого» HTML через HTML Tidy может помочь в качестве первого прохода? Может быть стоит посмотреть, если вы можете получить документ, который будет хорошо сформирован, возможно, вы можете загрузить его как обычный XML-файл с помощью DomDocument.
@Twan Вам не нужен DTD для DOMDocument для анализа пользовательского XML. Просто используйте DOMDocument->load()
, и пока XML хорошо сформирован, он может его прочитать.
После того, как вы получите файлы, которые будут хорошо сформированы, вот когда вы можете начать смотреть на синтаксические анализаторы XML, до этого вы SOL Lok Alejo сказали, что вы можете посмотреть HTML TIDY , но похоже, что это специфично для HTML, и я не знаю Не знаю, как это будет с вашими пользовательскими элементами.
Я не считаю регулярные выражения действительным решением здесь
Пока у вас не будет хорошей формы, это может быть вашим единственным вариантом. После того, как вы получите документы на этот этап, вы будете в курсе функций DOM.
Посмотрите на Parser в порту Fit 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
Мое быстрое и грязное решение этой проблемы состояло в том, чтобы запустить цикл, который соответствует моему списку пользовательских тегов с регулярным выражением. Регулярное выражение не захватывает теги, в которых есть внутренний внутренний тег.
Когда есть совпадение, вызывается функция для обработки этого тега и возвращает «обработанный HTML». Если этот пользовательский тег находился внутри другого пользовательского тега, а родитель становится бездетным из-за того, что фактический HTML был вставлен вместо дочернего элемента, и он будет соответствовать регулярному выражению и обрабатываться на следующей итерации цикла.
Цикл заканчивается, когда нет никаких бездетных пользовательских тегов для соответствия. В целом это итеративный (цикл while) и не рекурсивный.
@Alan Storm
Ваш комментарий к моему другому ответу заставил меня подумать:
Когда вы загружаете HTML-файл с DOMDocument, он, похоже, выполняет некоторый уровень очистки re: хорошо корректный, НО требует, чтобы все ваши теги были законными тегами HTML. Я ищу что-то, что делает первое, но не позже. (Алан Шторм)
Запустите регулярное выражение (извините!) По тегам, и когда он найдет тот, который не является допустимым элементом HTML, замените его допустимым элементом, который, как вы знаете, не существует ни в одном из документов ( blink
придет на ум. .) и присвойте ему значение атрибута с именем нелегального элемента, чтобы потом вы могли его вернуть. например:
$code = str_replace("<pseudo-tag>", "<blink rel=\"pseudo-tag\">", $code); // and then back again... $code = preg_replace('<blink rel="(.*?)">', '<\1>', $code);
очевидно, что код не будет работать, но вы получите общую идею?