Errores / advertencias de PHP DOMDocument en etiquetas html5

105

He intentado analizar el código HTML5 para poder establecer atributos / valores dentro del código, pero parece que DOMDocument (PHP5.3) no admite etiquetas como <nav>y <section>.

¿Hay alguna forma de analizar esto como HTML en PHP y manipular el código?


Código para reproducir:

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

Error

Advertencia: DOMDocument :: loadHTML (): Tag nav no válido en Entity, línea: 4 en /home/wbkrnl/public_html/new-mvc/1.php en la línea 17

Advertencia: DOMDocument :: loadHTML (): sección de etiqueta no válida en Entity, línea: 10 en /home/wbkrnl/public_html/new-mvc/1.php en la línea 17

Klaas Sangers
fuente
¡Ops, para mí loadHTML($HTML5)devuelve FALSO (falla)! Necesito cambiar las nuevas etiquetas a DIV ... No es solo un problema de "advertencias" en mi pantalla.
Peter Krauss
2
Este problema se informó para PHP en bugs.php.net/bug.php?id=60021 que a su vez dio lugar a una solicitud de función en el libxml2 subyacente: bugzilla.gnome.org/show_bug.cgi?id=761534
cweiske

Respuestas:

193

No, no hay forma de especificar un tipo de documento en particular para usar, o de modificar los requisitos del existente.

Su mejor solución viable será deshabilitar el informe de errores con libxml_use_internal_errors:

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML('...');
libxml_clear_errors();
día solitario
fuente
1
¡Ops, para mí loadHTML($HTML5)devuelve FALSO (falla)! Necesito cambiar las nuevas etiquetas a DIV ...
Peter Krauss
21
¿Alguna razón por la que el analizador DOM integrado de php7 todavía no puede manejar HTML5? Han pasado 6 años desde que se envió esta respuesta.
Super Cat
1
@SuperCat Todo depende de la biblioteca libxml subyacente.
solitario
6
--- sin mencionar que HTML5 no es XML, nunca fue, ha sido ni será ...
Kevin_Kinsey
2
Actualización 2019 : la advertencia aún se activa, sin embargo, loadHTMLahora acepta etiquetas HTML5.
9

Tu tambien puedes hacer

@$dom->loadHTML($htmlString);
Ilker Mutlu
fuente
16
La supresión de errores no es una forma adecuada de abordar este problema.
Klaas Sangers
6
@KlaasSangers Hasta que tengamos una implementación DOM no lisiada, me temo que es (ya sea a través @o libxml_*)
Dan Lugg
6
sí, en este caso específico, la supresión de errores es la mejor solución, en mi opinión. a menos que sepa que el HTML que va a cargar, se supone que es 100% HTML válido según la definición de PHP. que en mi experiencia, nunca es el caso.
hanshenrik
@KlaasSangers ... ¿por qué no?
Nick Manning
PHP8 "El operador @ ya no silencia los errores fatales. Es posible que este cambio revele errores que nuevamente estaban ocultos antes de PHP 8. ¡Asegúrese de configurar display_errors = Off en sus servidores de producción!" stitcher.io/blog/new-in-php-8
marcus
7

Puede filtrar los errores que obtiene del analizador. Según otras respuestas aquí, desactive el informe de errores en la pantalla y luego repita los errores y muestre solo los que desee:

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

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

Aquí hay un print_r()error de un solo:

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

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

Al hacer coincidir el messagey / o el code, estos se pueden filtrar con bastante facilidad.

halfer
fuente
2

No parece haber una forma de eliminar las advertencias pero no los errores. PHP tiene constantes que se supone que hacen esto, pero no parecen funcionar. Esto es lo que DEBERÍA funcionar, pero no porque (¿error?) ....

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

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

user2782001
fuente
De acuerdo con esta publicación, stackoverflow.com/a/41845049/937477 ese error se ha solucionado
mmmmm
1
Para ser pedante, eso no es HTML5 válido. Los elementos personalizados deben tener un guión de acuerdo con la especificación w3c.github.io/webcomponents/spec/custom/…
Greg
@ Greg Es bueno saberlo. Es solo una prueba para demostrar que el analizador xml reconocerá que la etiqueta no es válida, pero la ignorará debido a la bandera.
user2782001
0

Esto funcionó para mí:

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

Si necesita la etiqueta de encabezado, cambie el encabezado con una etiqueta div y use una identificación. Por ejemplo:

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

No es la mejor solución, pero dependiendo de la situación puede resultar útil.

Buena suerte.

Emiliano Sangoi
fuente
-5

Las etiquetas HTML5 casi siempre usan atributos como id, class, etc. Entonces el código para reemplazar 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
fuente