Gestire i documenti HTML con 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 it Toni 
    Tiveron
    AboutTheAuthor:[A small biography about the author]
    Guido adora Perl per la sua flessibilità e per la sua rapidità 
    come linguaggio per script. Apprezza il motto di Perl: "C'è più 
    di un modo per fare le cose" che rispecchia la libertà e le 
    possibilità offerte dal mondo dell'opensource.
    Abstract:[Here you write a little summary]
    Se volete gestire un sito web con più di 10 pagine HTML, presto vi 
    renderete conto che averete la necessità di ricorrere ad un 
    programma che vi possa aiutare.
    La maggior parte del software tradizionale processa riga per riga (o
    addirittura carattere per carattere).
    Sfortunanatamente le righe di un file non hanno alcun valore 
    in SGML/XML/HTML. Questo tipo di file si basa sui tag (ovvero parole 
    chiave) HTML::TagReader è un modulo che richede risorse moderare per 
    processare un file costituito con dei tag. 
    Questo articolo parte dal presupposto che voi conosciare il 
    linguaggio Perl abbastanza bene. Potete dare un'occhiata ai miei
    articoli sul Perl per
    prendervi confidenza.
    ArticleIllustration:[This is the title picture for your
    article]
    
    ArticleBody:[The article body]
    Introduzione
    Tradizionalmente i file si sono sempre basati sulla riga. Un 
    classico esempio possono essere i file di configurazione di Unix, 
    come per esempio, /etc/hosts, /etc/passwd,... Esistono anche sistemi 
    operativi datati che hanno specifiche funzioni per estrarre il 
    contenuto di un file riga per riga.
 SGML/XML/HTML sono invece 
    bastati sulle tag, e quindi la semplice riga perde di significato, 
    tuttavia gli editor di testi ed il pensiero umano sono ancora in 
    qualche modo legati al concetto di riga. 
     
    Questo è particolarmente vero di grossi file HTML che sono 
    costituiti da svariate righe di codice. Esistono strumenti come
    "Tydy" per permettere di avere una formattazione del codice HTML e 
    renderlo più leggibile. Tuttavia essi ricorrono sempre all`idea di 
    riga e non di tag ed l'HTML è per l'appunto basato du tag! Il codice 
    HTML potrebbe essere paragonato al codice C. Teoricamente potreste 
    scrivere l'intero codice su di una sola riga, ma nessuno lo fa. 
    Divvrebbe illegibile!
    Tuttavia voi vi aspettate che un sistema di controllo della sintassi 
    di un file HTML vi scriva "ERRORE: alla riga nuermo ...." piuttosto 
    che "ERRORE al  tag 4123". Questo in quanto l'editor che andate ad 
    utilizzare vi permette facilmente di raggiungere la riga in 
    questione. 
     
    Quello che ci serve, quindi, è un semplice e leggero sistema di 
    controllo per controllare il file HTML tag per tag e, nello 
    stesso tempo, tenere traccia della riga che stiamo analizzando .
    Una possibile soluzione
    Il modo convezionale di leggere un file in Perl è quello di 
    ricorrere al'operatore while(<FILEHANDLE>). Questo 
    permette di leggere i dati riga per riga e di assegnarne il 
    contentuto alla variabile $_. Perchè il Perl si comporta così? 
    Perchè ricorre ad una variabile interna detta INPUT_RECORD_SEPARATOR 
    ($RS o $/) ove all'interno della stessa viene definito "\n" come 
    carattere di fine riga. Se definite $/=">" allora Perl utilizzerà 
    ">" come carattere di fine riga. 
    Il seguente script in Perl formatterà il testo hmtl in modo che ogni 
    riga termini sempre con ">":
    perl -ne 'sub BEGIN{$/=">";} s/\s+/ /g; print
    "$_\n";' file.html
    un file html che apparirà nel seguente modo
<html><p>il vostro testo qui</p></html>
    diverrà
<html>
<p>
il vostro testo qui</p>
</html>
    Un aspetto molto importante di questo modo di procedere non è di 
    certo la sua più lineare leggibilità. Per lo svlippatore software è 
    più importante che ie dati sia correttamente trattari dalle funzioni,
    tag per tag. Questo rende molto semplice la possbilità di ricerche
    di tag, come per esemio "<a href="..." anche se nel codice 
    originale le parole chiavi "a" ed "html" fossero su righe diverse. 
     
    Cambiando il valore di "$/" (INPUT_RECORD_SEPARATOR) non si avrà nessun
    sovraccarico del sistema ed il tutto sarà molto veloce. Sarebbe anche possibile ricorrere
    all'operatore di uguaglianza ed utilizzare le espressioni (ovvero più stringhe)
    come iteratori e quindi processare il file per mezzo di
    espressioni predefinite. Questo è ovviamente un poco più complesso e 
    meno veloce nell'esecuzione, ma nonostante tutto, molto utilizzato. 
     
     Ma allora qual'è il problema? Il titolo di questo articolo 
     recita:  "HTML::TagReader". Noi fino ad ora abbiamo parlato di 
     soluzioni molto semplici che non richiedono alcun modulo esterno. 
     Ci deve essere, quindi, qualcosa che non va nella soluzione che ho
     proposto fino ad ora:
     
      - Purtroppo la maggior parte dei file HTML presenti sono 
      imperfetti. Vi sono milioni di pagine che, per esempio, contengono 
      del codice C che, se scritto in HTML, appare così:
       if ( limit > 3) ....
       invece di
       if ( limit > 3) ....
      In HTML "<" dovrebbe essere l`inizio di un tag e ">" ne
      dovrebbe essere la sua chiusura. Nessuno di essi dovrebbe mai 
      apparire nel testo stesso. Questo però non è sempre così e molti 
      browser mostrano entrambi gli stili in modo corretto, nascondendo 
      quindi l`eventuale errore.
      
       
      - Cambiare il valore di "$/" influisce sull'intero programma. Se 
      volete processare un altro file, riga per riga, mentre sta 
      trattando il file html, potreste incappare in molti problemi.
      
       
    
    In altre parole, vi sono pochissimi casi in sui si possa ricorrere 
    all'utilizzo della viariabile "$/" (INPUT_RECORD_SEPARATOR).
    Ho alcuni programmi d'esempio per voi che sfruttano il sistema fino 
    a qui descritto. Ho comunque perferito assegnare alla variabile "$/" 
    il valore "<" in quanto i browser web non sono in grado di
    gestire il carattere "<" se posizionato erroneamente al contrario 
    di quanto avviene con il carattere ">", e comunque sono molte 
    meno le pagine web con il carattere "<" posizionato erroneamente 
    che non quelle con il carattere ">".
    Questo semplice programma l'ho chiamato tr_tagcontentgrep
    (un click per vederlo) e all'interno del medesimo potete anche 
    vedere il codice che ho utilizzato per tenere traccia del numero di 
    riga. tr_tagcontentgrep può anche essere utilizzato per cercare una 
    stringa di un tag all'interno del file medesimo (per esempio "img"). 
    La ricerca di parte del tag può anche espandersi su più righe. 
    Vediamo un esempio:
    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 risolve i due problemi che si hanno quando si 
    ricorre alla modifica della variabile INPUT_RECORD_SEPARATOR ed 
    offre un sistema molto più apprezzabile per separare il testo dai 
    tag. Oltretutto non è avido di risorse come HTML:Parser ed offre 
    anche la possibilità di interfacciarsi meglio con noi: ci fornisce 
    un metodo per leggere da tag a tag. 
     
     Abbiamo divagato fin troppo. Ecco come usarlo. Prima di tutto 
     dovrete scrivere  
     use HTML::TagReader; 
     all'interno del vosto codice per poter caricare in memoria questo 
     modulo. Per utilizzarlo dovrete semplicemente scrivere
     my $p=new HTML::TagReader "filename"; 
     per analiazzare il file "filename" ed otterrete un oggetto nella
     variabile $p. Ora potete chiamare la variabile $p->gettag(0) o
     $p->getbytoken(0) per ottenere il prossimo tag. gettag ci 
     restituisce un solo tag (quella strana scritta tra < e >), 
     mentre getbytoken ci restituisce il testo contenuto e ci dice anche 
     se si tratti di testo o di un ulteriore tag. Con queste funzioni 
     risulta molto facile processare file html. Ecco che diviene uno 
     strumento essenziale per mantere grossi siti web. La sintassi 
     completa e una spiegazione più esaustiva può essere trovata sulla 
     pagina
     del manuale di HTML::TagReader. 
     
     Eccoci ora ad un vero esempio di funzionamento del programma. Ci 
     faremmo stampare i titoli dei documenti html che gli sottoporremo:
#!/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:
    Come funziona? Andiamo al leggere il file html per mezzo di $p->getbytoken(0)
    e quando troviamo la stringa <title> o <Title> o
    <TITLE> (ci sono restituiti come $tagtype equivalente a "title")
    andremmo ad assegnare un flag ($printnow) per iniziare la stampa del 
    titolo e non appena troveremo la stringa </title> 
    interromperemo la stampa.
    
     Utilizzare il programma come qui di seguito mostrato:
    htmltitle file.html somedir/index.html
     file.html:4: the cool perl page
     somedir/index.html:9: joe's homepage
    
    Certo tutto questo lo possiamo integrare anche con il programma 
    tr_tagcontentgrep. Sicuramente un poco più breve e più semplice da 
    scrivere:
#!/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";
    }
  }
}
    Lo script ora è molto breve e non ha particolari strumenti per 
    gestire gli errori, ma è completamente funzionale. Per cercare i tag 
    che contengano al loro interno la stringra "gif" dovremmo digitare: 
    
    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 ulteriore esempio? Qui abbiamo un programma che rimuove il tag 
    inerente la modifica dei caratteri, ovvero i tag: <font...> e
    </font>. Questo tipo di tag viene spesso utilizzato in maniera 
    esagerata da alcuni scadenti edito grafici per html e spesso questo 
    massiccio uso crea problemi guardando le pagine con diversi browser 
    e con diverse risoluzioni video. Questa versione semplificata 
    rimuove tutti i tag "font". Nessuno vi vieta di modificarla per far 
    si che rimuova solo determinate caratteristiche dei caratteri (il 
    tipo, il colore, la dimensione) lasciando il resto del tag intatto.
#!/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:
    Come potete notare è molto semplice scrivere programmi molto utili
    con ppchissime righe di codide.
    Il sorgente del pacchetto HTML::TagReader contiene alcuni esempi ed
    applicazioni del pacchetto stesso (trovate i riferimenti a ciò alla
    fine dell'articolo):
    
      - tr_blck -- controlla la presenza di link non validi nella
      pagine HTML
 
      - tr_llnk -- ci mostra la lista dei link nel file HTML 
 
      - tr_xlnk -- espande i link che puntano ad una cartella nel file 
      indice della medesima
 
      - tr_mvlnk -- modifica i tag nei file HTML per mezzo dei comandi
      di perl.
 
      - tr_staticssi -- espande le direttive SSI #include virtual e
      #exec cmd trasformando la pagina in html statico.
 
      - tr_imgaddsize -- aggiunge il flag altezza (height=) e
      larghezza (width=) dell'immagine al tag <img
      src=...>
 
    
    tr_xlnk and tr_staticssi sono molto utili quando vogliate creare dei 
    cdrom partendo da un sito web. Per esempio, quando digitate
    http://www.linuxfocus.org/ il server web vi farà vedere il seguente 
    indirizzo http://www.linuxfocus.org/index.html (caricherà 
    automaticamente la pagina index.html). Se tuttavia copiare tutti i 
    file del sito web sul cdrom ed accedete al cdrom con il vostro 
    browser web, vedete solo una lista di file e cartelle invece del 
    file index.html. La prima società che fece la prima edizione su 
    cdrom di _LF_ fece questo errore e fù assai scomodo consulatare il 
    cdrom. Ora utilizzano tr_xlnk per ottenere i dati da mettere sul 
    cdrom, e, difatti, ora i cdrom funzionano perfettamente. 
     
    Sono sicuro che troverete HTML::TagReader uno strumento molto ultile
    I am sure you will find HTML::TagReader useful. Happy programming!
    Bibliografie e riferimenti