Ошибки / предупреждения PHP DOMDocument о html5-тегах

105

Я пытался разобрать HTML5-код, чтобы установить атрибуты / значения в коде, но, похоже, DOMDocument (PHP5.3) не поддерживает такие теги, как <nav> и<section> .

Есть ли способ разобрать это как HTML в PHP и манипулировать кодом?


Код для воспроизведения:

<?php
$dom = new DOMDocument();
$dom->loadHTML("<!DOCTYPE HTML>
<html><head><title>test</title></head>
<body>
<nav>
  <ul>
    <li>first
    <li>second
  </ul>
</nav>
<section>
  ...
</section>
</body>
</html>");

ошибка

Предупреждение: DOMDocument :: loadHTML (): тег nav недействителен в Entity, строка: 4 в /home/wbkrnl/public_html/new-mvc/1.php в строке 17

Предупреждение: DOMDocument :: loadHTML (): раздел тега недопустим в Entity, строка: 10 в /home/wbkrnl/public_html/new-mvc/1.php в строке 17

Клаас Сэнджерс
источник
Опс, у меня loadHTML($HTML5)возвращается FALSE (сбой)! Мне нужно заменить новые теги на DIV ... Проблема не только в "предупреждениях" на моем экране.
Питер Краусс
2
Об этой проблеме для PHP было сообщено на странице bugs.php.net/bug.php?id=60021, что, в свою очередь, породило запрос функции в базовом libxml2: bugzilla.gnome.org/show_bug.cgi?id=761534
cweiske

Ответы:

193

Нет, невозможно указать конкретный тип документа для использования или изменить требования к существующему.

Лучшее работоспособное решение - отключить отчеты об ошибках с помощью libxml_use_internal_errors:

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML('...');
libxml_clear_errors();
одинокий день
источник
1
Опс, у меня loadHTML($HTML5)возвращается FALSE (сбой)! Мне нужно изменить новые теги на DIV ...
Питер Краусс
21
Есть ли причина, по которой встроенный в DOM парсер php7 все еще не может обрабатывать HTML5? Прошло 6 лет с тех пор, как был отправлен этот ответ.
Super Cat
1
@SuperCat Все зависит от базовой библиотеки libxml.
lonesomeday
6
--- не говоря уже о том, что HTML5 - это не XML, никогда не был, не был и не будет ...
Kevin_Kinsey 09
2
Обновление 2019 : предупреждение по-прежнему отображается, но loadHTMLтеперь фактически принимает теги HTML5.
9

Вы также можете сделать

@$dom->loadHTML($htmlString);
Илькер Мутлу
источник
16
Подавление ошибок - неправильный способ решения этой проблемы.
Клаас Сэнджерс
6
@KlaasSangers Пока у нас не будет нестандартной реализации DOM, я боюсь, что это будет (либо через, @либо libxml_*)
Дэн Лугг
6
да, на мой взгляд, в данном конкретном случае подавление ошибок - лучшее решение. если вы не знаете, что HTML-код, который вы будете загружать, должен быть на 100% действительным HTML согласно определению PHP. что, по моему опыту, никогда не бывает.
hanshenrik
@KlaasSangers ... почему бы и нет?
Ник Мэннинг,
PHP8 «Оператор @ больше не заглушает фатальные ошибки. Возможно, это изменение может выявить ошибки, которые снова были скрыты до PHP 8. Не забудьте установить display_errors = Off на ваших производственных серверах!» stitcher.io/blog/new-in-php-8
Маркус
7

Вы можете фильтровать ошибки, которые вы получаете от парсера. В соответствии с другими ответами здесь отключите отображение ошибок на экране, а затем перебирайте ошибки и показывайте только те, которые вы хотите:

libxml_use_internal_errors(TRUE);
// Do your load here
$errors = libxml_get_errors();

foreach ($errors as $error)
{
    /* @var $error LibXMLError */
}

Вот одна print_r()из ошибок:

LibXMLError Object
(
    [level] => 2
    [code] => 801
    [column] => 17
    [message] => Tag section invalid

    [file] => 
    [line] => 39
)

Путем сопоставления на messageи / или codeих можно довольно легко отфильтровать.

халфер
источник
2

Кажется, нет способа убрать предупреждения, но не ошибки. В PHP есть константы, которые должны делать это, но, похоже, они не работают. Вот что ДОЛЖНО работать, но не работает, потому что (ошибка?) ....

 $doc=new DOMDocument();
 $doc->loadHTML("<tagthatdoesnotexist><h1>Hi</h1></tagthatdoesnotexist>", LIBXML_NOWARNING );
 echo $doc->saveHTML();

http://php.net/manual/en/libxml.constants.php

user2782001
источник
Согласно этому сообщению stackoverflow.com/a/41845049/937477 , что ошибка была исправлена
ммммм
1
Чтобы быть педантичным, это недопустимый HTML5. Пользовательские элементы должны иметь дефис в соответствии со спецификацией w3c.github.io/webcomponents/spec/custom/…
Грег
@ Грег Полезно знать. Это просто тест, демонстрирующий, что синтаксический анализатор xml распознает недействительный тег, но проигнорирует его из-за флага.
user2782001 03
0

Это сработало для меня:

$html = file_get_contents($url);

$search = array("<header>", "</header>", "<nav>", "</nav>", "<section>", "</section>");
$replace = array("<div>", "</div>","<div>", "</div>", "<div>", "</div>");
$html = str_replace($search, $replace, $html);

$dom = new DOMDocument();
$dom->loadHTML($html);

Если вам нужен тег заголовка, измените заголовок с помощью тега div и используйте идентификатор. Например:

$search = array("<header>", "</header>");
$replace = array("<div id='header1'>", "</div>");

Это не лучшее решение, но в зависимости от ситуации может быть полезно.

Удачи.

Эмилиано Сангой
источник
-5

Теги HTML5 почти всегда используют такие атрибуты, как id, class и т. Д. Итак, код для замены будет:

$html = file_get_contents($url);
$search = array(
    "<header", "</header>", 
    "<nav", "</nav>", 
    "<section", "</section>",
    "<article", "</article>",
    "<footer", "</footer>",
    "<aside", "</aside>",
    "<noindex", "</noindex>",
);
$replace = array(
    "<div", "</div>",
    "<div", "</div>", 
    "<div", "</div>",
    "<div", "</div>",
    "<div", "</div>",
    "<div", "</div>",
    "<div", "</div>",
);
$html = str_replace($search, $replace, $html);
$dom = new DOMDocument();
$dom->loadHTML($html);
Сергей Калужский
источник