Использование флага LIBXML_HTML_NOIMPLIED с фрагментом html генерирует неправильные теги:
$str = '<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>'; $doc = new DOMDocument(); $doc->loadHTML($str, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); echo $doc->saveHTML();
Выходы:
<p>Lorem ipsum dolor sit amet.<p>Nunc vel vehicula ante.</p></p>
Я нашел хаки, чтобы обойти это с помощью регулярных выражений, но это побеждает цель использования DOM. Я тестировал это с несколькими версиями libxml и php, последними с libxml 2.9.2, php 5.6.7 (Debian Jessy). Любые предложения оценили.
LIBXML_HTML_NOIMPLIED
выполняется с помощью используемого вами LIBXML_HTML_NOIMPLIED
. Похоже, он недостаточно стабилен для вашего дела.
Также вы можете не использовать его по причинам, связанным с портабельностью, например, у меня есть один PHP 5.4.36 с Libxml 2.7.8 под рукой, который не поддерживает LIBXML_HTML_NOIMPLIED
(Libxml> = 2.7.7), но позже LIBXML_HTML_NODEFDTD
(Libxml> = 2.7.8).
Я знаю этот способ справиться с этим. Когда вы загружаете фрагмент, вы переносите его в элемент <div>
:
$doc->loadHTML("<div>$str</div>");
Это помогает направлять DOMDocument на нужную вам структуру.
Затем вы можете извлечь этот контейнер из самого документа:
$container = $doc->getElementsByTagName('div')->item(0); $container = $container->parentNode->removeChild($container);
Затем удалите всех детей из документа:
while ($doc->firstChild) { $doc->removeChild($doc->firstChild); }
Теперь документ полностью пуст, и теперь вы можете снова добавить детей. К счастью, элемент контейнера <div>
мы удалили ранее, поэтому мы можем добавить его:
while ($container->firstChild ) { $doc->appendChild($container->firstChild); }
Затем фрагмент можно получить с помощью известного метода saveHTML :
echo $doc->saveHTML();
Что дает в вашем сценарии:
<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>
Эта методология немного отличается от существующего материала здесь, на сайте (см. Ссылки, которые я приводил ниже), поэтому пример сразу:
$str = '<p>Lorem ipsum dolor sit amet.</p><p>Nunc vel vehicula ante.</p>'; $doc = new DOMDocument(); $doc->loadHTML("<div>$str</div>"); $container = $doc->getElementsByTagName('div')->item(0); $container = $container->parentNode->removeChild($container); while ($doc->firstChild) { $doc->removeChild($doc->firstChild); } while ($container->firstChild ) { $doc->appendChild($container->firstChild); } echo $doc->saveHTML();
Я также рекомендую ссылочный вопрос о том, как сохранитьHTML DOMDocument без оболочки HTML? для дальнейшего чтения, а также один о inner-html
Параметр LIBXML_HTML_NOIMPLIED
не является ошибкой, он просто плохо документирован. Чтобы устранить проблему, оберните свою строку ввода <html>…</html>
, обработайте свой HTML-код и отделите его от вывода. LibXML требует корневой узел и обрабатывает первый элемент, который он находит в качестве корневого узла, удаляя (неправильно расположенный) закрывающий тег, который он находит на полпути, а затем выводит закрывающий тег первого элемента, который он нашел в конце документ. Это логично, когда вы видите это с точки зрения (Lib) XML.