Administrando HTML com o 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 pt Bruno Sousa
AboutTheAuthor:[A small biography about the author]
O Guido gosta de Perl porque � uma linguagem de scripting bastante
flex�vel e r�pida. Ele gosta do lema do Perl "H� mais do que um modo para
fazer as coisas" o que reflecte a liberdades e as possibilidades que se t�m
quando se lida com o opensource.
Abstract:[Here you write a little summary]
Se quiser administrar um website com mais do que 10 p�ginas HTML, ent�o cedo
se aperceber� que necessita de alguns programas para lhe dar suporte.
A maior parte do software tradicional l� linha a linha (ou caracter a
caracter). Infelizmente as linhas n�o t�m significado nos ficheiros
SGML/XML/HTML, estes ficheiros s�o baseados em Tags. O HTML::TagReader � um
m�dulo leve para procesasr um ficheiro atrv�s de Tags.
Este artigo assume que j� conhece bem o Perl. D� uma vista de olhos
nos meus toturiais de Perl
(Janeiro 2000) se quiser aprender Perl.
ArticleIllustration:[This is the title picture for your
article]
ArticleBody:[The article body]
Introdu��o
Os ficheiros tradicionais t�m sido � base de linhas. Exemplo disto s�o
os ficheiros de configura��o do Unix, como /etc/hosts, /etc/passwd...
Existem, inclusiv� sistemas operativos que t�m fun��es para ler e escrever
linha a linha.
Os ficheiros SGML/XML/HTML s�o baseados em Tags, as linhas aqui n�o t�m
significado, contudo os editores de texto e os humanos s�o, ainda de algum
modo, baseados em linhas.
Normalmente, os ficheiros grandes HTML, consistem em
diversas linhas de c�digo HTML. Existem utilit�rios como o "Tidy" para
identar html e o tornar leg�vel. Usamos linhas apesar do HTML ser baseado
em Tags e n�o linhas. Pode compar�-lo ao c�digo C. Teoricamente podia
escrever todo o c�digo numa s� linha. Ningu�m faz isto. Seria Ileg�vel.
Assim espera que o analisador de sintaxe HTML escreva: "ERROR:
linha..." em vez de "ERROR ap�s tag 4123". Isto porque o seu editor de
texto lhe permite saltar facilmente para a dada linha.
O que aqui � preciso � um bom e leve modo de processar um ficheiro
HTML Tag a Tag mantendo o n�mero de linhas
Uma poss�vel solu��o
O modo normal de ler um ficheiro em Perl � usar o operador
while(<FILEHANDLE>). Isto l� linha a linha, passando cada
linha para a vari�vel $_. Porque � que o Perl faz isto? O Perl tem uma
vari�vel interna chamada INPUT_RECORD_SEPARATOR ($RS ou $/) onde est�
definido que "\n" � o fim de uma linha. Se definir $/=">" ent�o o Perl
usa ">" como "fim de linha". O seguinte comando Perl reformata o texto
html para terminar sempre em ">":
perl -ne 'sub BEGIN{$/=">";} s/\s+/ /g; print
"$_\n";' file.html
Um ficheiro html que se parece com
<html><p>algum texto aqui</p></html>
tornar-se-�
<html>
<p>
algum texto aqui</p>
</html>
Contudo o conte�do principal ainda n�o � leg�vel. Para o programador de
software � importante que os dados sej�o passados �s fun��es no seu c�digo
Tag a Tag. Com isto ser� f�cil procurar "<a href= ..." mesmo que o
c�digo original tenha "a" e "href" em linhas separadas.
Alterar a vari�vel "$/" (INPUT_RECORD_SEPARATOR) faz com que o
overhead do processamento seja m�nimo e muito r�pido. � ainda poss�vel
usar o operador de igualdade (match) e as express�es regulares como
iteradores e processar o ficheiro com express�es regulares. Isto � um pouco
mais complicado e mais lento mas tamb�m � usado.
Onde � que est� o porblema?? O t�tulo deste artigo dizia:
HTML::TagReader mas at� agora estive todo o tempo a falar de uma
solu��o mais simples e que n�o requer m�dulos extra. Deve haver algo de
errado com esta solu��o:
- Praticamente todos os ficheiros HTML no mundo t�m erros. Existem
milh�es de p�ginas que cont�m, por exemplo, exemplos de c�digo C que
aparecem no c�digo HTML do seguinte modo:
if ( limit > 3) ....
em vez de
if ( limit > 3) ....
No HTML "<" devia come�ar uma tag e >" devia termin�-la. Nenhuma
deles deve aparecer sozinha algures no texto.
A maioria dos browser apresenta ambas correctamente escondendo o
erro.
- Alterar o "$/" afecta todo o programa. Se quiser processar outro
ficheiro linha a linha enquanto l� o ficheiro html, ent�o tem um
problema.
Por outras palavras, s� em casos especiais � que � poss�vel usar o "$/"
(INPUT_RECORD_SEPARATOR).
Contudo ainda tenho um bom exemplo para
si e que usa o que at� ent�o discutimos. Contudo define o "$/" para "<"
porque os browsers n�o conseguem lidar t�o bem com um "<" mal colocado
como com um ">" por isso existem menos p�ginas web com "<" mal
colocados do que com ">"
O programa chama-se tr_tagcontentgrep
(clique para ver) pode tamb�m ver no c�digo como manter o n�mero da
linha. O tr_tagcontentgrep pode ser usado para pesquisar uma string
(por exemplo "img") numa Tag mesmo que esta ocupe v�rias linhas. Algo
como:
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 resolve dois dos problemas da modifica��o do
INPUT_RECORD_SEPARATOR e oferece um modo mais simp�tico de separar o
texto das tags. N�o � t�o pesado quanto um HTML::Parser completo mas
oferece o que quer quando processa o c�digo html: Um m�todo para ler
Tag por Tag.
Basta de palavras. Eis o modo como se usa, primeiro deve escrever
use HTML::TagReader;
no seu c�digo para carregar o m�dulo, depois chama
my $p=new HTML::TagReader "filename";
para abrir o ficheiro "filename" e obter a refer�ncia para um objecto
retornardo em $p. Agora pode chamar $p->gettag(0) ou
$p->getbytoken(0) para obter a pr�xima Tag. O gettag s� retorna Tags
(algo entre < e >) enquanto que o getbytoken retorna tamb�m o
texto entre as tags e diz-lhe o que � (se uma Tag ou Texto). Com estas
fun��es � muito f�cil de processar ficheiros html. O Essencial para
manter um grande website. A descrip��o total pode ser encontrada
na p�gina man
do HTML::TagReader.
Eis agora um programa de exemplo real. Imprime os t�tulos dos
documentos de um dado n�mero de documentos:
#!/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:
Como � que trabalha? Lemos o ficheiro html com $p->getbytoken(0)
quando encontramos <title> ou <Title> ou <TITLE>
(elas s�o retornadas como $tagtype iguais a "title") e depois define-se
uma flag ($printnow) para iniciar a impress�o e quando encontramos
</title> paramos a impress�o.
Usa o programa deste modo:
htmltitle file.html somedir/index.html
file.html:4: the cool perl page
somedir/index.html:9: joe's homepage
Claro que � poss�vel implementar o tr_tagcontentgrep a partir do
HTML::TagReader. Um pouco mais curto e simples de escrever:
#!/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";
}
}
}
A script � pequena e n�o tem muita valida��o de erros mas por outro
lado est� totalmente funcional. Para pesquisar por tags que contenham a
string "gif" pode digitar:
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">
Mais um exemplo? Eis aqui um programa que obtem todas as tags
<font...> e </font> do seu c�digo html. Estas tags de
fontes s�o usadas de um modo massivo por editores gr�ficos de html
pobres causando bastantes problemas quando se v�em p�ginas em
diferentes browsers e com resolu��es de ecr� diferentes. Esta vers�o
simples remove todas as Tags de fontes. Pode alter�-la para somente
remover aquelas que definem a fontface ou tamanho e que mant�m a cor
inalterada.
#!/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:
Como pode ver � muito f�cil escrever programas �teis somente com algumas
linhas de c�digo.
O pacote com o c�digo fonte do HTML::TagReader (ver refer�ncias)
cont�m j� algumas das aplica��es do HTML::TagReader:
- tr_blck -- verifica os links relativos n�o naveg�veis nas p�ginas
HTML
- tr_llnk -- lista os links nos ficheiros HTML
- tr_xlnk -- expande os links dos direct�rios num ficheiro index
com links.
- tr_mvlnk -- modifica as tags dos ficheiros HTML com os comandos
perl.
- tr_staticssi -- expande as directivas SSI #include virtual e
#exec cmd e produz uma p�gina est�tica html.
- tr_imgaddsize -- adiciona width=... e height=... a <img
src=...>
O tr_xlnk e o tr_staticssi s�o bastante �teis quando pretende fazer um
CDrom do seu Website. Por exemplo, o servidor d�-lhe
http://www.linuxfocus.org/index.html mesmo que tenha digitado
http://www.linuxfocus.org/ (sem o index.html). Se passar todos os
ficheiros e direct�rios para o CD e aceder ao CD com um browser
directamente (ficheiro:/mnt/cdrom) ent�o ver� uma listagem do
direct�rio em vez do index.html. A companhia que fez o primeiro CD da
_LF_ fez este erro e foi terr�vel usar o CD. Agora que obt�m os dados
atrav�s do tr_xlnk os CDs est�o a trabalhar.
Tenho a certeza que encontrar� o HTML::TagReader �til. Divirta-se a
programar!
Refer�ncias