Как заставить HTML5 работать с DOMDocument?
Я пытаюсь разобрать HTML-код с DOMDocument, сделать что-то вроде изменений в нем, а затем собрать его обратно в строку, которую я отправляю на вывод.
Но есть несколько вопросов, касающихся разбора, что означает, что то, что я отправляю в DOMDocument, не всегда возвращается в том же виде:)
Вот список:
-
используя - > loadHTML:
- форматирует мой документ независимо от настроек
preserveWhitespace
и formatOutput
(теряя пробелы в предварительно отформатированном тексте)
- дает мне ошибки, когда у меня есть теги html5, такие как
<header>
, <footer>
и т.д. Но они могут быть подавлены, поэтому я могу жить с этим.
- создает несогласованную разметку - например, если я добавлю элемент
<link ... />
(с самозакрывающимся тегом), после разбора/сохраненияHTML вывод будет <link .. >
-
используя - > loadXML:
- кодирует такие объекты, как
>
из тегов <style>
или <script>
: body > div
становится body > div
- все теги закрываются одинаково, например
<meta ... />
становится <meta...></meta>
; но это может быть исправлено с помощью регулярного выражения.
Я не пробовал HTML5lib, но я бы предпочел DOMDocument вместо настраиваемого анализатора по причинам производительности.
Update:
Так как Honeymonster, упомянутый с использованием CDATA, исправляет основную проблему с loadXML.
Можно ли каким-либо образом предотвратить самозакрытие всех пустых тегов HTML, помимо определенного набора, без использования регулярного выражения?
Сейчас у меня есть:
$html = $dom->saveXML($node);
$html = preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', function($matches){
// ignore only these tags
$xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param' ,'meta');
// if a element that is not in the above list is empty,
// it should close like `<element></element>` (for eg. empty `<title>`)
return in_array($matches[1], $xhtml_tags) ? "<{$matches[1]}{$matches[2]} />" : "<{$matches[1]}{$matches[2]}></{$matches[1]}>";
}, $html);
который работает, но он также будет выполнять замены в содержимом CDATA, чего я не хочу...
Ответы
Ответ 1
К сожалению, или, возможно, к счастью, domdocument разработан, чтобы не пытаться сохранить форматирование из исходного документа. Это упрощает управление внутренним состоянием парсера, сохраняя все элементы одного и того же стиля. Afaik most parsers создаст представление дерева в памяти и не беспокоится о текстовом форматировании, пока пользователь не запросит такие. Вот почему ваши закрытые теги выводятся с отдельными закрывающими тегами. Хорошей новостью является то, что это не имеет значения.
Что касается тегов стиля и тегов script, получающих <>
, преобразованных в <>
, вы можете избежать конверсии, окружая содержимое соответствующего элемента с помощью рекомендуемых тегов cdata:
<style>
/*<![CDATA[*/
body > div {
width: 50%;
}
/*]]>*/
</style>
Комментарий /* */
вокруг деклараций cdata заключается в том, чтобы разрешить разбитым клиентам, которые не знают о разделах cdata, и вместо этого обрабатывать объявления как код CSS. Если вы используете документ только внутри, вы можете опустить окружение комментариев /* */
и иметь только объявление cdata. Вы можете столкнуться с проблемами с вышеупомянутыми сломанными клиентами, если вы манипулируете документом, а затем отправляете его в браузер, не проверяя, что комментарии /* */
сохранены; Я не уверен, сохранит ли domdocument эти или нет.
Ответ 2
Используйте html5lib. Он может анализировать html5 и производить DOMDocument. Пример:
require_once '/path/to/HTML5/Parser.php';
$dom = HTML5_Parser::parse('<html><body>...');
Документация
Ответ 3
Если вы хотите поддерживать HTML5, не трогайте DOMDocument вообще.
В настоящее время лучшим вариантом является https://github.com/Masterminds/html5-php
Раньше лучшим вариантом было https://github.com/html5lib/html5lib-php, но, как говорится в описании, оно "в настоящее время не поддерживается". И это был статус с октября 2011 года, поэтому я больше не задерживаю дыхание.
Я не использовал html5-php
в производстве, поэтому я не могу представить реальный мир об этом. Я использовал html5lib-php
в производстве, и я бы сказал, что он корректно обрабатывает хорошо сформированные документы, но он имеет неожиданные ошибки с некоторыми простыми синтаксическими ошибками. С другой стороны, кажется, что алгоритм внедрения агентства принятия решений и некоторые другие странные угловые случаи правильно. Если бы html5lib-php
все еще поддерживался, я бы предпочел это. Однако, поскольку в настоящее время я предпочитаю использовать html5-php
и, возможно, помогать в исправлении оставшихся ошибок.
Ответ 4
Я пробовал как html5lib, так и html5php, но не работал с HTML, который мне предоставили. Альтернативой, которая была в состоянии проанализировать HTML, была: https://github.com/ivopetkov/html5-dom-document-php
Основной класс расширяет собственный DomDocument PHP.
Ответ 5
При инициализации domDocument выполните следующие действия:
$dom = new DOMDocument(5, 'UTF-8');