Как заставить HTML5 работать с DOMDocument?

Я пытаюсь разобрать HTML-код с DOMDocument, сделать что-то вроде изменений в нем, а затем собрать его обратно в строку, которую я отправляю на вывод.

Но есть несколько вопросов, касающихся разбора, что означает, что то, что я отправляю в DOMDocument, не всегда возвращается в том же виде 🙂

Вот список:

  1. используя -> loadHTML :

    • форматирует мой документ независимо от настроек preserveWhitespace и formatOutput (теряя пробелы в предварительно отформатированном тексте)
    • дает мне ошибки, когда у меня есть теги html5, такие как <header> , <footer> и т. д. Но они могут быть подавлены, поэтому я могу жить с этим.
    • создает несогласованную разметку – например, если я добавлю элемент <link ... /> (с самозакрывающимся тегом), после разбора / сохраненияHTML вывод будет <link .. >
  2. using -> loadXML :

    • кодирует объекты типа > из тегов <style> или <script> : body > div становится body &gt; div body &gt; div
    • все теги закрываются одинаково, например <meta ... /> становится <meta...></meta> ; но это может быть исправлено с помощью регулярного выражения.

Я не пробовал HTML5lib, но я бы предпочел DOMDocument вместо настраиваемого анализатора по причинам производительности


Обновить:

Так, как 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, чего я не хочу …

К сожалению, или, возможно, к счастью, domdocument разработан, чтобы не пытаться сохранить форматирование из исходного документа. Это упрощает управление внутренним состоянием парсера, сохраняя все элементы одного и того же стиля. Afaik most parsers создаст представление дерева в памяти и не беспокоится о текстовом форматировании, пока пользователь не запросит такие. Вот почему ваши закрытые теги выводятся с отдельными закрывающими тегами. Хорошая новость заключается в том, что это не имеет значения.

Что касается тегов стиля и тегов скриптов, получивших <> преобразованный в &lt;&gt; , вы можете избежать конверсии, окружая содержимое элемента, о котором идет речь, с рекомендуемыми тегами cdata:

 <style> /*<![CDATA[*/ body > div { width: 50%; } /*]]>*/ </style> 

Комментарий /* */ вокруг деклараций cdata заключается в том, чтобы разрешить разбитым клиентам, которые не знают о разделах cdata, и вместо этого обрабатывать объявления как код CSS. Если вы используете документ только внутри, вы можете опустить окружения /* */ comment и иметь только объявление cdata. Вы можете столкнуться с проблемами с вышеупомянутыми сломанными клиентами, если вы манипулируете документом, а затем отправляете его в браузер, не проверяя, чтобы /* */ комментарии сохранялись; Я не уверен, сохранит ли domdocument эти или нет.

Используйте html5lib . Он может анализировать html5 и производить DOMDocument. Пример:

 require_once '/path/to/HTML5/Parser.php'; $dom = HTML5_Parser::parse('<html><body>...'); 

Документация

Если вы хотите поддерживать HTML5, не трогайте DOMDocument.

В настоящее время лучшим вариантом является https://github.com/Masterminds/html5-php

Раньше лучшим вариантом был https://github.com/html5lib/html5lib-php, но, как говорится в описании, он «в настоящее время не поддерживается». И это был статус с октября 2011 года, поэтому я больше не задерживаю дыхание.

Я не использовал html5-php в производстве, поэтому я не могу представить реальный мир об этом. Я использовал html5lib-php в производстве, и я бы сказал, что он правильно html5lib-php хорошо сформированные документы, но он имеет неожиданные ошибки с некоторыми простыми синтаксическими ошибками. С другой стороны, кажется, что алгоритм внедрения агентства принятия решений и некоторые другие странные угловые случаи правильно. Если html5lib-php все еще поддерживался, я бы предпочел это. Однако, поскольку в настоящее время я предпочитаю использовать html5-php и, возможно, помогать исправлять оставшиеся ошибки там.

Я пробовал как html5lib, так и html5php, но ни один из них не работал с HTML, который мне предоставили. Альтернативой, которая могла анализировать HTML, была: https://github.com/ivopetkov/html5-dom-document-php

Основной класс расширяет собственный DomDocument PHP.

При инициализации domDocument выполните следующие действия:

 $dom = new DOMDocument(5, 'UTF-8');