В имеющейся разметке HTML присутствует некорректный синтаксис, который нужно удалить . Подобная чистка упрощает разбор и гарантирует, что создаваемые страницы соответствуют тандартам.
Воспользуйтесь расширением PHP Tidy. Это расширение при помощи популярной мощной библиотеки HTML Tidy превращает хаотичную мешанину из тегов в синтаксически корректную, соответствующую стандартам разметку HTML или XHTML. Пример показывает, как исправить некорректный файл.
|
$fixed = tidy_repair_file('bad.html'); file_put_contents('good.html', $fixed); |
В библиотеке HTML Tidy за прошедшее время были собраны многочисленные правила и функции для исправления разнообразных нарушений HTML. К счастью, чтобы пользоваться Tidy, вам не нужно знать об этих правилах. Просто передайте имя файла функции tidy_repair_file() , и вы получите исправленную версию. Допустим, файл bad.html содержит следующую разметку:
|
<img src="monkey.jpg"> <b>I <em>love</b> monkeys</em>. |
Листинг записывает в файл good.html следующую разметку:
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN"> <html> <head> <title></title> </head> <body> <img src="monkey.jpg"> <b>I <em>love</em> monkeys</b>. </body> </html> |
Решение Tidy содержит множество конфигурационных параметров, влияющих на генерируемый результат. Параметры передаются tidy_repair_file() во втором аргументе, который содержит массив параметров и значений. В листинге используется параметр output-xhtml , который приказывает Tidy сгенерировать действительную разметку XHTML. Листинг Генерирование XHTML с использованием Tidy
|
$config = array('output-xhtml' => true); $fixed = tidy_repair_file('bad.html', $config); file_put_contents('good.xhtml', $fixed); |
Код записывает в good.xhtml следующий вывод:
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> <img src="monkey.jpg" /> <b>I <em>love</em> monkeys</b>. </body> </html> |
Если источником является строка, а не файл, используйте tidy_repair_string(). Функция получает первый аргумент с разметкой HTML, а не имя файла. Исправленный код XHTML, сгенерированный Tidy, также предоставляет возможность пометки HTML без использования регулярных выражений. После того как разметка HTML будет преобразована в синтаксически корректный документ XHTML, ее можно корректно обработать и преобразовать функциями PHP DOM. В коде показано, как это делается. Разметка веб-страницы средствами Tidy и DOM
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
$body = ' <p>I like pickles and herring.</p> <a href="pickle.php"><img src="pickle.jpg"/>A pickle picture</a> I have a herringbone-patterned toaster cozy. <herring>Herring is not a real HTML element!</herring> '; $words = array('pickle','herring'); $patterns = array(); $replacements = array(); foreach ($words as $i => $word) { $patterns[] = '/' . preg_quote($word) . '/i'; $replacements[] = "<span class='word-$i'>$word</span>"; } /* Приказать Tidy сгенерировать разметку XHTML */ $xhtml = tidy_repair_string($body, array('output-xhtml' => true)); /* XHTML загружается как документ XML */ $doc = new DOMDocument; $doc->loadXml($xhtml); /* При преобразовании HTML в документ XHTML * Tidy размещает входную разметку HTML в элементе <body/> * документа XHTML */ $body = $doc->getElementsByTagName('body')->item(0); /* Обход всех текстовых узлов и пометка слов в случае необходимости */ $xpath = new DOMXpath($doc); foreach ($xpath->query("descendant-or-self::text()", $body) as $textNode) { $replaced = preg_replace($patterns, $replacements, $textNode->wholeText); if ($replaced !== $textNode->wholeText) { $fragment = $textNode->ownerDocument->createDocumentFragment(); /* Гарантирует, что подузлы <span/> будут созданы правильно */ $fragment->appendXml($replaced); $textNode->parentNode->replaceChild($fragment, $textNode); } } /* Построение разметки XHTML, состоящей из всего содержимого <body/> */ $markedup = ''; foreach ($body->childNodes as $node) { $markedup .= $doc->saveXml($node); } print $markedup; |
Тут команда preg_replace() для добавления разметки применяется ко всем текстовым узлам дерева DOM, полученного при загрузке исправленной версии входной разметки HTML в объект DOMDocument . А самое замечательное — мы можем быть уверены в том, что замена применяется только к тексту. Любая некорректная разметка HTML, которая могла бы сбить с толку регулярное выражение для поиска HTML в коде, будет исправлена Tidy до создания объекта DOMDocument. Недостаток такого решения заключается в том, что в зависимости от степе-
ни некорректности входной разметки HTML результат преобразования Tidy может оказаться не таким, какой вы ожидаете. Вот какой результат выдает код:
|
<p>I like <span class="word-0">pickle</span>s and <span class="word-1">herring </span>.</p> <a href="pickle.php"><img src="pickle.jpg" />A <span class="word-0">pickle </span> picture</a> I have a <span class="word-1">herring</span>bone-patterned toaster cozy. <span class="word-1">herring</span> is not a real HTML element! |
Обратите внимание на последнюю часть: herring
is not a real HTML element! .
Поскольку не является действительным элементом XHTML, Tidy удаляет и , оставляя внутренний текст. Это разумная мера для получения действительного документа XHTML, но если вы к ней не готовы, она может стать неприятным сюрпризом.