Erros / avisos do PHP DOMDocument em tags html5

105

Tenho tentado analisar o código HTML5 para definir atributos / valores dentro do código, mas parece que DOMDocument (PHP5.3) não oferece suporte a tags como <nav>e <section>.

Existe alguma maneira de analisar isso como HTML em PHP e manipular o código?


Código para reproduzir:

<?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>");

Erro

Aviso: DOMDocument :: loadHTML (): Tag nav inválida em Entity, linha: 4 em /home/wbkrnl/public_html/new-mvc/1.php na linha 17

Aviso: DOMDocument :: loadHTML (): seção de tag inválida em Entity, linha: 10 em /home/wbkrnl/public_html/new-mvc/1.php na linha 17

Klaas Sangers
fonte
Ops, para mim loadHTML($HTML5)retorna FALSE (falha)! Preciso trocar as novas tags por DIVs ... Não é apenas um problema de "avisos" na minha tela.
Peter Krauss
2
Este problema foi relatado para o PHP em bugs.php.net/bug.php?id=60021 que por sua vez gerou uma solicitação de recurso na libxml2 subjacente: bugzilla.gnome.org/show_bug.cgi?id=761534
cweiske

Respostas:

193

Não, não há como especificar um doctype específico a ser usado ou modificar os requisitos do existente.

Sua melhor solução viável será desativar o relatório de erros com libxml_use_internal_errors:

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML('...');
libxml_clear_errors();
solitário
fonte
1
Ops, para mim loadHTML($HTML5)retorna FALSE (falha)! Preciso mudar as novas tags para DIVs ...
Peter Krauss
21
Alguma razão pela qual o analisador DOM embutido do php7 ainda não consegue lidar com HTML5? Já se passaram 6 anos desde que esta resposta foi enviada.
Super Cat
1
@SuperCat Tudo depende da biblioteca libxml subjacente.
solitário dia
6
--- sem mencionar que HTML5 não é XML, nunca foi, foi, nem será ...
Kevin_Kinsey
2
Atualização 2019 : o aviso ainda é disparado, mas loadHTMLagora aceita tags HTML5.
9

Você também poderia fazer

@$dom->loadHTML($htmlString);
Ilker Mutlu
fonte
16
A supressão de erros não é uma maneira adequada de lidar com esse problema.
Klaas Sangers de
6
@KlaasSangers Até termos uma implementação de DOM não deficiente, infelizmente é (através de @ou libxml_*)
Dan Lugg
6
sim, neste caso específico, a supressão de erros é a melhor solução, na minha opinião. a menos que você saiba que o HTML que estará carregando, é considerado um HTML 100% válido pela definição do PHP. o que, na minha experiência, nunca é o caso.
hanshenrik
@KlaasSangers ... por que não?
Nick Manning,
PHP8 "O operador @ não silencia mais os erros fatais. É possível que esta alteração revele erros que estavam ocultos antes do PHP 8. Certifique-se de definir display_errors = Off em seus servidores de produção!" stitcher.io/blog/new-in-php-8
marcus
7

Você pode filtrar os erros obtidos no analisador. De acordo com outras respostas aqui, desative o relatório de erros na tela e, em seguida, repita os erros e mostre apenas aqueles que você deseja:

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

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

Aqui está um print_r()erro único:

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

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

Combinando no messagee / ou no code, eles podem ser filtrados facilmente.

halfer
fonte
2

Não parece haver uma maneira de eliminar os avisos, mas não os erros. O PHP tem constantes que supostamente fazem isso, mas elas parecem não funcionar. Aqui está o que DEVE funcionar, mas não funciona porque (bug?) ....

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

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

user2782001
fonte
De acordo com esta postagem stackoverflow.com/a/41845049/937477 esse bug foi corrigido
mmmmm
1
Só para ser pedante, isso não é HTML5 válido. Os elementos personalizados devem ter um hífen de acordo com a especificação w3c.github.io/webcomponents/spec/custom/…
Greg
@Greg Bom saber. É apenas um teste para demonstrar que o analisador xml reconhecerá que a tag não é válida, mas ignore-a por causa do sinalizador.
user2782001
0

Isso funcionou para mim:

$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);

Se você precisar da tag de cabeçalho, altere o cabeçalho com uma tag div e use um id. Por exemplo:

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

Não é a melhor solução, mas dependendo da situação pode ser útil.

Boa sorte.

Emiliano Sangoi
fonte
-5

As tags HTML5 quase sempre usam atributos como id, classe e assim por diante. Portanto, o código de substituição será:

$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);
Sergey Kaluzhsky
fonte