PHP DOMDocument erreurs / avertissements sur les balises html5

105

J'ai essayé d'analyser le code HTML5 afin de pouvoir définir des attributs / valeurs dans le code, mais il semble que DOMDocument (PHP5.3) ne prend pas en charge les balises comme <nav>et <section>.

Existe-t-il un moyen d'analyser cela en HTML en PHP et de manipuler le code?


Code à reproduire:

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

Erreur

Attention: DOMDocument :: loadHTML (): Tag nav invalide dans Entity, ligne: 4 dans /home/wbkrnl/public_html/new-mvc/1.php en ligne 17

Avertissement: DOMDocument :: loadHTML (): Section de balise invalide dans Entity, ligne: 10 dans /home/wbkrnl/public_html/new-mvc/1.php à la ligne 17

Klaas Sangers
la source
Ops, pour moi loadHTML($HTML5)renvoie FALSE (échec)! J'ai besoin de changer les nouvelles balises en DIV ... Ce n'est pas seulement un problème de "warnings" sur mon écran.
Peter Krauss
2
Ce problème a été signalé pour PHP à bugs.php.net/bug.php?id=60021 qui à son tour a engendré une demande de fonctionnalité dans la libxml2 sous-jacente: bugzilla.gnome.org/show_bug.cgi?id=761534
cweiske

Réponses:

193

Non, il n'y a aucun moyen de spécifier un doctype particulier à utiliser ou de modifier les exigences de l'existant.

La meilleure solution possible sera de désactiver les rapports d'erreurs avec libxml_use_internal_errors:

$dom = new DOMDocument;
libxml_use_internal_errors(true);
$dom->loadHTML('...');
libxml_clear_errors();
seul jour
la source
1
Ops, pour moi loadHTML($HTML5)renvoie FALSE (échec)! Je dois changer les nouvelles balises en DIV ...
Peter Krauss
21
Une raison pour laquelle l 'analyseur DOM intégré de php7 ne peut toujours pas gérer HTML5? Cela fait 6 ans que cette réponse a été soumise.
Super Cat
1
@SuperCat Tout dépend de la bibliothèque libxml sous-jacente.
lonesomeday
6
--- sans oublier que HTML5 n'est pas XML, n'a jamais été, n'a été, ni ne sera ...
Kevin_Kinsey
2
Mise à jour 2019 : l'avertissement est toujours déclenché, mais loadHTMLaccepte désormais les balises HTML5.
9

Tu pourrais aussi faire

@$dom->loadHTML($htmlString);
Ilker Mutlu
la source
16
La suppression des erreurs n'est pas une manière appropriée de traiter ce problème.
Klaas Sangers
6
@KlaasSangers Jusqu'à ce que nous ayons une implémentation DOM non paralysée, j'ai peur que ce soit le cas (soit à travers @ou libxml_*)
Dan Lugg
6
oui, dans ce cas précis, la suppression des erreurs est la meilleure solution, à mon avis. à moins que vous ne sachiez que le HTML que vous allez charger est censé être 100% HTML valide selon la définition de PHP. ce qui, d'après mon expérience, n'est jamais le cas.
hanshenrik
@KlaasSangers ... pourquoi pas?
Nick Manning
PHP8 "L'opérateur @ ne fait plus taire les erreurs fatales. Il est possible que ce changement révèle des erreurs qui étaient à nouveau cachées avant PHP 8. Assurez-vous de définir display_errors = Off sur vos serveurs de production!" stitcher.io/blog/new-in-php-8
marcus
7

Vous pouvez filtrer les erreurs que vous obtenez de l'analyseur. Comme pour les autres réponses ici, désactivez le rapport d'erreurs à l'écran, puis parcourez les erreurs et n'affichez que celles que vous voulez:

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

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

Voici une print_r()erreur unique:

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

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

En faisant correspondre le messageet / ou le code, ceux-ci peuvent être filtrés assez facilement.

licol
la source
2

Il ne semble pas y avoir de moyen de supprimer les avertissements mais pas les erreurs. PHP a des constantes censées faire cela, mais elles ne semblent pas fonctionner. Voici ce qui DEVRAIT fonctionner, mais pas parce que (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
la source
Selon ce message, stackoverflow.com/a/41845049/937477, ce bogue a été corrigé
mmmmm
1
Juste pour être pédant, ce n'est pas du HTML5 valide. Les éléments personnalisés doivent avoir un trait d'union selon la spécification w3c.github.io/webcomponents/spec/custom/…
Greg
@Greg Bon à savoir. C'est juste un test pour démontrer que l'analyseur XML reconnaîtra que la balise n'est pas valide, mais l'ignorera à cause de l'indicateur.
user2782001
0

Cela a fonctionné pour moi:

$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 vous avez besoin de la balise d'en-tête, changez l'en-tête avec une balise div et utilisez un identifiant. Par exemple:

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

Ce n'est pas la meilleure solution mais selon la situation, cela peut être utile.

Bonne chance.

Emiliano Sangoi
la source
-5

Les balises HTML5 utilisent presque toujours des attributs tels que id, class, etc. Ainsi, le code de remplacement sera:

$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
la source