Как заставить HTML5 работать с DOMDocument? - программирование
Подтвердить что ты не робот

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

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

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

Вот список:

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

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

    • кодирует такие объекты, как > из тегов <style> или <script>: body > div становится body &gt; 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, чего я не хочу...

4b9b3361

Ответ 1

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

Что касается тегов стиля и тегов script, получающих <>, преобразованных в &lt;&gt;, вы можете избежать конверсии, окружая содержимое соответствующего элемента с помощью рекомендуемых тегов 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');