G�rer le HTML avec Perl, HTML::TagReader
ArticleCategory: [Choose a category, do not translate
this]
Webdesign
AuthorImage:[Here we need a little image from you]
TranslationInfo:[Author + translation history. mailto: or
http://homepage]
original in en Guido
Socher
en to fr Georges Tarbouriech
AboutTheAuthor:[A small biography about the author]
Guido aime Perl parce que c'est un langage de script tr�s versatile et
rapide.
Il aime la devise de Perl "Il y a plus d'une fa�on de le
faire" parce qu'elle refl�te la libert� et les possibilit�s offertes par
l'"opensource".
Abstract:[Here you write a little summary]
Si vous g�rez un site web de plus de 10 pages HTML, vous vous rendrez vite
compte qu'il est imp�ratif d'utiliser quelques programmes pour vous aider
dans cette t�che.
La plupart des logiciels traditionnels lisent les fichiers ligne par ligne
(ou caract�re par caract�re).
Malheureusement les lignes n'ont aucun sens dans les fichiers SGML/XML/HTML.
Les fichiers SGML/XML/HTML reposent sur des balises. HTML::TagReader est un
module tr�s l�ger permettant d'examiner un fichier par balise.
Cet article suppose que vous connaissez bien Perl. Penchez-vous sur
mes tutoriels Perl (Janvier
2000) si vous souhaitez apprendre ce langage.
ArticleIllustration:[This is the title picture for your
article]
ArticleBody:[The article body]
Introduction
Traditionnellement les fichiers ont �t� bas�s sur la ligne. Quelques
exemples sont fournis par les fichiers de configuration d'Unix comme
/etc/hosts, /etc/passwd .... Certains syst�mes d'exploitation plus anciens
poss�daient m�me des fonctions permettant de retrouver et d'�crire des donn�es
ligne � ligne.
Les fichiers SGML/XML/HTML sont bas�s sur des balises, les lignes n'ayant
ici aucune signification, m�me si les �diteurs de texte et les individus
sont encore d�pendants des lignes.
Les gros fichiers HTML en particulier, consistent en de nombreuses lignes de code HTML
pour votre serveur. Il existe m�me des outils comme "Tidy" pour indenter le
HTML et le rendre lisible. Bien qu'il repose sur des tags, nous utilisons
quand m�me des lignes pour le HTML. Nous pourrions le comparer � du code C.
Th�oriquement, vous pouvez �crire le code complet sur une seule ligne.
Personne ne fait une chose pareille : ce serait illisible.
Par cons�quent, vous attendez d'un correcteur de syntaxe HTML qu'il �crive
"ERROR: line ..." plut�t que "ERROR after tag 4123" (erreur apr�s la balise
4123). Ceci parce que votre �diteur de texte vous permet facilement de
sauter � une ligne donn�e du fichier.
Il nous faut donc un moyen l�ger et efficace
pour examiner un fichier HTML balise par balise tout en conservant la
r�f�rence aux num�ros de lignes.
Une solution �ventuelle
La mani�re habituelle de lire un fichier avec Perl consiste � utiliser
l'op�rateur while(<FILEHANDLE>). Celui-ci lit les donn�es ligne par
ligne et passe chacune d'elles � la variable $_ . Pourquoi Perl
proc�de-t-il ainsi ? Perl poss�de une variable interne nomm�e
INPUT_RECORD_SEPARATOR ($RS ou $/) dans laquelle il est d�fini que "\n"
correspond � la fin d'une ligne. Si vous d�finissez
$/=">", Perl utilisera alors ">" comme "end of line" (fin de ligne).
La commande de script Perl suivante reformate le texte html de mani�re � ce
qu'il finisse toujours par ">":
perl -ne 'sub BEGIN{$/=">";} s/\s+/ /g; print
"$_\n";' file.html
Un fichier html qui ressemble �
<html><p>some text here</p></html>
deviendra
<html>
<p>
some text here</p>
</html>
Toutefois, l'essentiel n'est pas la lisibilit�. Pour le d�veloppeur,
l'important c'est que les donn�es soient pass�es aux fonctions de son code
balise par balise. Ainsi, il sera facile de rechercher
"<a href= ..." m�me si le fichier html d'origine contient "a" et "href"
sur des lignes diff�rentes.
Modifier le "$/" (INPUT_RECORD_SEPARATOR) ne provoque aucune surcharge
et tout est tr�s rapide. Il est �galement possible d'utiliser l'op�rateur
"match" et des expressions r�guli�res servant d'it�rateur; on peut alors
examiner le fichier avec des expressions r�guli�res. C'est un peu plus
compliqu� et lent mais souvent utilis�.
O� est le probl�me ?? Le titre de cet article contient
HTML::TagReader, mais jusqu'� pr�sent je n'ai parl� que d'une solution plus
simple qui n'a aucun besoin de modules suppl�mentaires.
Quelque chose ne convient pas dans cette solution :
- La plupart des fichiers HTML au monde sont impropres. Il existe des
millions de pages qui contiennent des exemples de code C qui
en code HTML ressemblent �
if ( limit > 3) ....
au lieu de
if ( limit > 3) ....
En HTML "<" d�bute une balise et ">" la termine. Aucun des deux ne
doit appara�tre dans le texte.
La plupart des navigateurs afficheront les deux versions correctement
et cacheront l'erreur.
- Modifier le "$/" affecte l'ensemble du programme. Si vous voulez
examiner un autre fichier ligne � ligne pendant que vous lisez le fichier
html, vous allez rencontrer un probl�me.
En d'autres termes, il n'est possible que dans certains cas d'utiliser le
"$/" (INPUT_RECORD_SEPARATOR).
J'ai encore un exemple de programme utile
correspondant � ce dont nous avons parl� jusqu'ici. Il d�finit "$/" en
"<". Les navigateurs ne g�rent pas aussi bien un "<" erron� qu'un
">" et par cons�quent il existe beaucoup moins de pages html contenant un
"<" incorrect qu'un ">" mal plac�. Le programme se nomme tr_tagcontentgrep
(cliquez pour le visualiser) et vous pouvez voir dans le code comment
conserver le num�ro de ligne.
tr_tagcontentgrep peut �tre utilis� pour rechercher ("grep") une
cha�ne (par ex."img") dans une balise, y compris si la balise s'�tend sur
plusieurs lignes. Comme ceci :
tr_tagcontentgrep -l img file.html
index.html:53: <IMG src="../images/transpix.gif" alt="">
index.html:257: <IMG SRC="../Logo.gif" width=128
height=53>
HTML::TagReader
HTML::TagReader r�sout les deux probl�mes en modifiant le
INPUT_RECORD_SEPARATOR et offre ainsi un moyen beaucoup plus �l�gant de
s�parer le texte des balises. Il n'est pas aussi lourd qu'un v�ritable
HTML::Parser (analyseur de code HTML) et offre ce dont vous avez besoin pour
examiner du code html : une m�thode de lecture balise par balise.
Assez de bla-bla. Voici comment l'utiliser. Vous devez d'abord �crire
use HTML::TagReader;
dans votre code pour charger le module. Ensuite vous appelez
my $p=new HTML::TagReader "filename";
pour ouvrir le fichier "filename" et obtenir un objet r�f�rence renvoy�
dans $p. Vous pouvez maintenant appeler $p->gettag(0) ou
$p->getbytoken(0) pour atteindre la balise suivante. gettag ne renvoie
que le contenu des balises (ce qui se trouve entre <
et >) alors que getbytoken fournit �galement le texte contenu entre les
balises en vous indiquant la nature (balise ou texte). Gr�ce � ces fonctions
il est tr�s facile d'examiner les fichiers html. Essentiel pour g�rer un
gros site. Une description compl�te de la syntaxe se trouve dans la
page de manuel de
HTML::TagReader.
Voici un v�ritable programme exemple. Il affiche les titres des diff�rents
documents examin�s :
#!/usr/bin/perl -w
use strict;
use HTML::TagReader;
#
die "USAGE: htmltitle file.html [file2.html...]\n" unless($ARGV[0]);
my $printnow=0;
my ($tagOrText,$tagtype,$linenumber,$column);
#
for my $file (@ARGV){
my $p=new HTML::TagReader "$file";
# read the file with getbytoken:
while(($tagOrText,$tagtype,$linenumber,$column) = $p->getbytoken(0)){
if ($tagtype eq "title"){
$printnow=1;
print "${file}:${linenumber}:${column}: ";
next;
}
next unless($printnow);
if ($tagtype eq "/title" || $tagtype eq "/head" ){
$printnow=0;
print "\n";
next;
}
$tagOrText=~s/\s+/ /; #kill newline, double space and tabs
print $tagOrText;
}
}
# vim: set sw=4 ts=4 si et:
Comment fonctionne-t-il ? Nous lisons le fichier html par
$p->getbytoken(0) et lorsque nous trouvons
<title> ou <Title> ou <TITLE> (ils sont renvoy�s en tant
que $tagtype eq "title") nous positionnons un drapeau ($printnow) pour
d�marrer l'affichage et nous arr�tons ce dernier lorsque nous rencontrons
</title>.
Vous utilisez ce programme de cette mani�re :
htmltitle file.html somedir/index.html
file.html:4: the cool perl page
somedir/index.html:9: joe's homepage
Bien s�r, il est possible d'activer le tr_tagcontentgrep ci-dessus
avec HTML::TagReader. C'est plus court et plus facile � �crire :
#!/usr/bin/perl -w
use HTML::TagReader;
die "USAGE: taggrep.pl searchexpr file.html\n" unless ($ARGV[1]);
my $expression = shift;
my @tag;
for my $file (@ARGV){
my $p=new HTML::TagReader "$file";
while(@tag = $p->gettag(0)){
# $tag[0] is the tag (e.g <a href=...>)
# $tag[1]=linenumber $tag[2]=column
if ($tag[0]=~/$expression/io){
print "$file:$tag[1]:$tag[2]: $tag[0]\n";
}
}
}
Le script est court et ne se pr�occupe pas trop de la gestion des erreurs
mais il est parfaitement fonctionnel. Pour extraire (grep) les balises
contenant la cha�ne "gif", tapez :
taggrep.pl gif file.html
file.html:135:15: <img src="images/2doc.gif" width=34
height=22>
file.html:140:1: <img src="images/tst.gif" height="164"
width="173">
Un autre exemple ? Voici un programme qui supprime toutes les balises
<font...> et </font> du code html. Ces balises de polices sont
parfois utilis�es en grande quantit� par quelques �diteurs html graphiques
mal �crits et posent de nombreux probl�mes lorsque les pages sont
visualis�es avec des navigateurs diff�rents sur des r�solutions diff�rentes.
Ce simple script �limine ces balises. Vous pouvez le modifier de fa�on
� ce qu'il ne supprime que les balises d�finissant la police ou la taille
tout en laissant la couleur inchang�e.
#!/usr/bin/perl -w
use strict;
use HTML::TagReader;
# strip all font tags from html code but leave the rest of the
# code un-changed.
die "USAGE: delfont file.html > newfile.html\n" unless ($ARGV[0]);
my $file = $ARGV[0];
my ($tagOrText,$tagtype,$linenumber,$column);
#
my $p=new HTML::TagReader "$file";
# read the file with getbytoken:
while(($tagOrText,$tagtype,$linenumber,$column) = $p->getbytoken(0)){
if ($tagtype eq "font" || $tagtype eq "/font"){
print STDERR "${file}:${linenumber}:${column}: deleting $tagtype\n";
next;
}
print $tagOrText;
}
# vim: set sw=4 ts=4 si et:
Comme vous le voyez, il est tr�s facile d'�crire des programmes utiles en
quelques lignes.
Le paquetage de code source de HTML::TagReader (voir r�f�rences)
contient quelques applications de HTML::TagReader:
- tr_blck -- v�rifie les liens relatifs bris�s dans des pages HTML
- tr_llnk -- liste les liens des fichiers HTML
- tr_xlnk -- �tend les liens vers des r�pertoires en liens vers des
fichiers index
- tr_mvlnk -- modifie les balises dans des fichiers HTML avec des
commandes perl.
- tr_staticssi -- �tend les directives SSI #include virtual et
#exec cmd et produit une page html statique.
- tr_imgaddsize -- ajoute width=... et height=... � <img
src=...>
tr_xlnk et tr_staticssi sont tr�s pratiques lorsque vous souhaitez cr�er un
CDRom � partir d'un site web. Le serveur web vous fournira par exemple
http://www.linuxfocus.org/index.html m�me si vous n'avez tap� que
http://www.linuxfocus.org/ (sans index.html). Toutefois, si vous vous
contentez de graver tous les fichiers et r�pertoires sur un CD et que vous
consultiez ce CD directement avec votre navigateur (file:/mnt/cdrom) vous
obtiendrez une liste de r�pertoires au lieu d'un fichier index.html.
La soci�t� qui a grav� le premier CD de _LF_ a fait cette erreur et le
r�sultat �tait catastrophique. Maintenant que les donn�es sont obtenues par
tr_xlnk les CD fonctionnent tr�s bien.
Je suis certain que trouverez HTML::TagReader tr�s pratique. Programmez
bien !
R�f�rences