loadHTML LIBXML_HTML_NOIMPLIED на фрагменте html генерирует неправильные теги

Использование флага 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). Любые предложения оценили.

Solutions Collecting From Web of "loadHTML LIBXML_HTML_NOIMPLIED на фрагменте html генерирует неправильные теги"

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

Рекомендации

  • Как сохранитьHTML DOMDocument без оболочки HTML?
  • Как получить innerHTML DOMNode?

Параметр LIBXML_HTML_NOIMPLIED не является ошибкой, он просто плохо документирован. Чтобы устранить проблему, оберните свою строку ввода <html>…</html> , обработайте свой HTML-код и отделите его от вывода. LibXML требует корневой узел и обрабатывает первый элемент, который он находит в качестве корневого узла, удаляя (неправильно расположенный) закрывающий тег, который он находит на полпути, а затем выводит закрывающий тег первого элемента, который он нашел в конце документ. Это логично, когда вы видите это с точки зрения (Lib) XML.