Page 1 sur 1

Un parser HTML des plus léger

Posté : 16 août 2008, 03:13
par Gofromiel
Bonjour,

Dans le l'optique de l'amélioration perpétuelle, je viens de mettre un grand coup au moteur de publication de mon CMS. J'utilisais jusqu'à présent preg_match_callback() pour traiter les gabarits, ce qui était assez lourd, et surtout n'autorisait pas la moindre imbrication de même type...

Ce matin j'ai donc réfléchi très fort et j'ai pondu (aïe) un parser HTML des plus simple, léger et merveilleux.

Il prend un texte HTML (ou XML) et crée un arbre de nœuds _texte_ et _marqueur_. Il est possible de préciser un espace de noms pour ne récupérer que les marqueurs de l'espace de noms (ce qui me sert pour mon CMS). On peut également préciser l'encodage (utf-8 par défaut bien sûr), les valeurs des attributs des marqueurs étant _désachappées_ pour la plus grande joie des grands et des petits.

Vous trouverez tout ça sur mon blog : Un parser HTML des plus rapide et léger

Un piti exemple qui utilise l'espace de noms 'wdp:'

Code : Tout sélectionner

<wdp:articles limit="5"> <ul> <wdp:foreach> <li>{this.title}</li> </wdp:foreach> </ul> </wdp:articles>
<?php

$parser = new WdHTMLParser();

$tree = $parser->parse($template, 'wdp:');

echo '<pre>' . print_r($true, true) . '</pre>';

?>

Code : Tout sélectionner

Array ( [0] => Array ( [name] => articles [args] => Array ( [limit] => 5 ) [children] => Array ( [0] => <ul> [1] => Array ( [name] => foreach [args] => Array ( ) [children] => Array ( [0] => <li>{this.title}</li> ) ) [2] => </ul> ) ) )

Posté : 16 août 2008, 11:31
par Sékiltoyai
C'est un parseur XML non ? Pourquoi ne pas simplement utiliser SimpleXML, il apporte quelquechose de plus ?

Posté : 16 août 2008, 18:29
par Hywan
(J'ai écrit un commentaire sur ton site à propos de ton parseur, je le remets ici) :
Hey :),

C'est pas mal mais j'ai quelques questions :
1. pourquoi ne pas utiliser les fonctions de PHP qui sont appropriées (voir <http://php.net/xml>) ? ;
2. pourquoi ne pas utiliser même SimpleXml (voir <http://php.net/simplexml>), quitte à faire un wrapper ? ;
3. pourquoi ne gères-tu pas les CDATA ?

Pour les questions 1 et 2, tu gagnerais en rapidité. SimpleXML est totalement écrit en C, c'est donc plus rapide. D'autant qu'il permet la gestion du DOM, XPath, etc. De plus, SimpleXML est installé sur toutes les machines PHP 5 par défaut. Concernant les fonctions PHP pour la gestion des documents XML, elles sont également écrites en C (on l'aurait deviné ;-)) et sont même disponibles depuis PHP 4.

Posté : 19 août 2008, 17:12
par Gofromiel
Comme le titre du post le laisse supposer, il s'agit d'un parser HTML et non XML. Évidement il digèrera très bien le XML mais c'est pour digérer du HTML lâche qu'il a été crée.

Pour mon CMS j'ai besoin d'un parser basique qui se contente de lire les marqueurs (si possible ceux de l'espace de noms précisés) et de renvoyer un arbre. Il lit des gabarits qui sont des morceaux de HTML dedans, avec des marqueurs de contrôle spécifiques. Je ne trouvais pas mon bonheur, alors je l'ai crée.

J'ai abandonné très vite l'idée d'utiliser SimpleXML avec le genre de gabarits suivant :

Code : Tout sélectionner

<div id="respond"> <h2>Poster un commentaire</h2> <wdp:comments:form> <wdp:choose> <wdp:when test="this.ok"><p>Merci de votre contribution.</p></wdp:when> <wdp:when test="this.missing"><p>Merci de remplir les champs obligatoires qui sont marqués d'une astérixe&nbsp;:</p></wdp:when> <wdp:when test="this.spam"> <p>Avec un score de {this.spam}, votre message est considéré comme du spam, ce qui peut arriver s'il est trop court ou pénible. Essayez donc d'écrire quelque chose d'intéressant ;-)</p> <p>Si vous avez la chance d'être membre du site, connectez-vous. Vos messages seront toujours les bienvenus, même s'ils sont courts et pénibles.</p></wdp:when> </wdp:choose> <wdp:otherwise>{this.form}</wdp:otherwise> </wdp:comments:form> </div> <div id="comments"> <wdp:comments order="asc"> <wdp:foreach> <div id="respond-{this.id}" class="comment {_foreach.even}"> <h4> <var>{_foreach.position}</var> <wdp:choose> <wdp:when test="this.url"> <a href="{this.url}">{this.author.entities()}</a> </wdp:when> <wdp:otherwise>{this.author.entities()}</wdp:otherwise> </wdp:choose> a écrit&nbsp;: <small> {this.created.ftime('%A %d %B %Y', NULL, true)} à {this.created.ftime('%H:%M', NULL, true)} </small> </h4> {this.contents.textmark()} </div> </wdp:foreach> </wdp:comments> </div>

Posté : 19 août 2008, 22:46
par Hywan
Pourquoi abandonner SimpleXML au juste ?

Posté : 19 août 2008, 23:16
par momox
Pourquoi abandonner SimpleXML au juste ?
A cause du code HTML, certaines fois dégueulasse, qui serait refusé par SimpleXML...

Posté : 20 août 2008, 01:58
par Hywan
Bah justement, c'est une sécurité de plus. C'est un peu bête comme argument :?, je dirais illogique en fait.

SimpleXML sait lire les DTD, plus facile pour faire ses propres espaces de nom pour son propre moteur de template non ? Et sous prétexte qu'un code serait mal écrit, il faut quand même le tolérer ? C'est ça que je trouve illogique …

Posté : 20 août 2008, 15:09
par Gofromiel
Essaie de parser le bout de code que j'ai donné plus haut avec SimpleXML. Ça demande juste trop de temps et d'investissement pour obtenir quelque chose de tout simple (un arbre). Vu la dizaine de gabarits de ce type que mon CMS doit interpréter pour générer les sites, SimpleXML me parait pénible...

J'ai aussi besoin que *seul* les marqueurs dans l'espace de noms 'wdp:' soient collectés, et que les autres (HTML) soient traités comme du texte (ce qu'ils sont du point de vue du gabarit). Est-ce que SimpleXML me permet de réaliser cela facilement ? Déjà qu'il est exceptionnellement pénible avec tout ce qui est échappé (e.g. &nbsp;...)

Posté : 20 août 2008, 15:25
par Hywan
Comme suggérer sur ton site en commentaire, tu peux faire un wrapper :).

Il faut comprendre que SimpleXML est très rapide face à PHP. C'est pour ça que j'insiste un peu. Et même utiliser SimpleXML + un wrapper serait plus rapide que PHP tout seul.