48 votes

Analyseur DOM autorisant le style HTML5 </ in <script> étiquette

Mise à jour: html5lib (en bas de la question) semble se rapprocher, j'ai juste besoin d'améliorer ma compréhension de la façon dont il est utilisé.

J'essaie de trouver un HTML5 compatible DOM parser pour PHP 5.3. En particulier, j'ai besoin d'accéder à la page suivante HTML CDATA à l'intérieur d'une balise de script:

<script type="text/x-jquery-tmpl" id="foo">
    <table><tr><td>${name}</td></tr></table>
</script>

La plupart des analyseurs ce sera la fin de l'analyse prématurément en raison HTML 4.01 se termine balise de script d'analyse quand il trouve ETAGO (</) à l'intérieur d'un <script> balise. Cependant, HTML5 permet de </ avant </script>. Tous les analyseurs j'ai essayé jusqu'à présent ont soit échoué, ou ils sont si mal documenté que je n'ai pas compris si elles travaillent ou non.

Mes exigences:

  1. Réel de l'analyseur, pas de regex hacks.
  2. Capacité de chargement complet des pages ou des fragments de HTML.
  3. Capacité à tirer script contenu arrière, la sélection par l'attribut id de la balise.

Entrée:

<script id="foo"><td>bar</td></script>

Exemple de défaut de sortie (pas de clôture, </td>):

<script id="foo"><td>bar</script>

Certains analyseurs et de leurs résultats:


DOMDocument (échoue)

Source:

<?php

header('Content-type: text/plain');
$d = new DOMDocument;
$d->loadHTML('<script id="foo"><td>bar</td></script>');
echo $d->saveHTML();

Sortie:

Warning: DOMDocument::loadHTML(): Unexpected end tag : td in Entity, line: 1 in /home/adam/public_html/2010/10/26/dom.php on line 5
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head><script id="foo"><td>bar</script></head></html>


FluentDOM (échoue)

Source:

<?php

header('Content-type: text/plain');
require_once 'FluentDOM/src/FluentDOM.php';
$html = "<html><head></head><body><script id='foo'><td></td></script></body></html>";
echo FluentDOM($html, 'text/html');

Sortie:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head></head><body><script id="foo"><td></script></body></html>


phpQuery (échoue)

Source:

<?php

header('Content-type: text/plain');

require_once 'phpQuery.php';

phpQuery::newDocumentHTML(<<<EOF
<script type="text/x-jquery-tmpl" id="foo">
<td>test</td>
</script>
EOF
);

echo (string)pq('#foo');

Sortie:

<script type="text/x-jquery-tmpl" id="foo">
<td>test
</script>


html5lib (passe)

Éventuellement prometteur. Puis-je obtenir le contenu de l' script#foo balise?

Source:

<?php

header('Content-type: text/plain');

include 'HTML5/Parser.php';

$html = "<!DOCTYPE html><html><head></head><body><script id='foo'><td></td></script></body></html>";
$d = HTML5_Parser::parse($html);

echo $d->saveHTML();

Sortie:

<html><head></head><body><script id="foo"><td></td></script></body></html>

11voto

Alex Points 5018

J'ai eu le même problème et apparemment, vous pouvez modifier votre chemin en chargeant le document au format XML et enregistrez-le au format HTML :)

 $d = new DOMDocument;
$d->loadXML('<script id="foo"><td>bar</td></script>');
echo $d->saveHTML();
 

Mais bien entendu, le balisage doit être exempt d’erreurs pour que loadXML fonctionne.

5voto

Alan Storm Points 82442

Re: html5lib

Vous cliquez sur l'onglet de téléchargement et de téléchargement de la version de PHP de l'analyseur.

Vous décompressez l'archive dans un dossier local

 tar -zxvf html5lib-php-0.1.tar.gz
 x html5lib-php-0.1/
 x html5lib-php-0.1/VERSION
 x html5lib-php-0.1/docs/
 ... etc

Vous modifiez les répertoires et créer un fichier nommé hello.php

cd html5lib-php-0.1
touch hello.php 

Vous placez le code PHP suivant dans hello.php

$html = '<html><head></head><body>
<script type="text/x-jquery-tmpl" id="foo">
<table><tr><td>${name}</td></tr></table>
</script> 
</body></html>';
$dom = HTML5_Parser::parse($html); 
var_dump($dom->saveXml()); 
echo "\nDone\n";

Vous exécutez hello.php à partir de la ligne de commande

php hello.php

L'analyseur de parser le document de l'arbre, et retourner un objet DOMDocument, qui peuvent être manipulés comme tout autre objet DOMDocument.

5voto

Thomas Weinert Points 31

FluentDOM utilise le DOMDocument mais bloque le chargement des avis et des avertissements. Il n'a pas son propre analyseur. Vous pouvez ajouter vos propres chargeurs (par exemple, celui qui utilise html5lib).

4voto

alex Points 186293

J'ai ajouté des balises de commentaire ( <!-- ... --> ) dans mes blocs de modèle jQuery (les blocs CDATA ont également échoué) et DOMDocument n'a pas touché le code HTML interne.

Ensuite, avant d’utiliser les modèles jQuery, j’écrivais un script pour supprimer les commentaires.

 $(function() {
    $('script[type="text/x-jquery-tmpl"]').text(function() {
        // The comment node in this context is actually a text node.
        return $.trim($(this).text()).replace(/^<!--([\s\S]*)-->$/, '$1');
    });
});
 

Pas idéal, mais je n'étais pas sûr d'une meilleure solution de contournement.

3voto

olaf Points 16

J'ai rencontré ce problème exact.

PHP Dom Document analyse le code html à l'intérieur d'une balise de script et qui peuvent effectivement conduire à un tout autre dom.

Depuis que je ne voulais pas utiliser une autre bibliothèque que DomDocument. J'ai écrit quelques lignes que des bandes de tout le contenu des scripts, puis vous faites ce que jamais vous avez besoin de le faire avec le dom document et ensuite vous mettez ce script contenu.

Évidemment, le script contenu n'est pas disponible à votre dom objet parce qu'il est vide.

Avec les lignes suivantes de code php, vous pouvez régler ce problème. Soyez averti que les balises de script dans les scripts des balises sera la cause de bug.

$scripts = array();
// this will select all script tags non-greedy. If you have a script tag in your script tag, it will cause problems.
preg_match_all("/((<script.*>)(.*))\/script>/sU", $html, $scripts);
// Make content of scripts empty
$html = str_replace($scripts[3], '', $html);

// Do DOM Document stuff here

// Put script contents back
$html = str_replace($scripts[2], $scripts[1], $html);

J'espère que cela aidera certaines personnes :-).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X