TagSoup: un parser HTML per Java

In questo articolo mostreremo come utilizzare la libreria (in formato jar) TagSoup giunta alla versione 1.2.

TagSoup è un parser SAX-compliant scritto in Java che, invece di effettuare il parsing di file XML, i quali sono per loro natura ben formati e validi, analizza file in formato HTML così come si trovano in rete: cioè in una sintassi molto delle volte non conforme agli standard dettati dalle Recommendation del W3C (http://www.w3.org/TR/html4/). TagSoup è progettato per tutti quegli sviluppatori che devono esaminare codice HTML con una applicazione che abbia qualche parvenza di un disegno razionale. Fornendo una interfaccia SAX, permette agli strumenti XML standard di  poter processare anche il codice HTML. TagSoup include anche un processore da riga di comando che legge i file HTML e può generare sia HTML pulito o XML ben formattato, che è una approssimazione molto vicina a XHTML.

Quello che TagSoup garantisce è di rendere i documenti ben formati: ad esempio chiude i tag di formattazione se non è stato fatto, gli attributi di default vengono inseriti in modo appropriato, e così via. La semantica di TagSoup è per molti versi molto simile a quella dei browser odierni, cioè provvede in automatico alla formattazione e al corretto innestamento dei tag, ad esempio il testo:

This is <B>bold, <I>bold italic, </b>italic, </i>normal text

viene correttamente riscritto come:

This is <b>bold, <i>bold italic, </i></b><i>italic, </i>normal text.

La prima cosa da fare è scaricare la libreria dalla seguente url:

http://ccil.org/~cowan/XML/tagsoup/

utilizzeremo la versione 1.2 che è l’ultima rilasciata al momento della stesura di questo articolo.

Siccome TagSoup è perfettamente compatibile con SAX, possiamo utilizzare un processore XPath per poter interrogare il nostro documento HTML. Per il nostro esempio utilizziamo Jaxen, il quale permette di interrogare file XML con una semplice sintassi testuale. Dato un particolare path del documento XML, il processore XPath ci restituisce il nodo o la lista dei nodi appartenenti a quel path.

Un processore XPath ha però bisogno di un documento parserizzato come albero DOM (tree DOM) in quanto esso deve poter ispezionare il documento in modo da poter andare sia in avanti che poter ritornare indietro (forward and backward looking), ha cioè bisogno di avere il documento completamente caricato in memoria, al contrario di SAX che lo parserizza in modo sequenziale, così che dati a cui si è acceduto in precedenza non possono essere riletti senza la rielaborazione dell’intero documento; per tale motivo utilizzeremo la libreria JDOM che contiene al suo interno una classe, chiamata SAXBuilder, che permette la conversione da SAX a DOM, in questo modo Jaxen può lavorare direttamente sugli alberi DOM.

Utilizziamo ora le librerie jar all’interno di un progetto Java che realizzeremo utilizzando Eclipse.

Creiamo un nuovo Progetto Java in Eclipse (File -> New -> Java Project), creiamo una cartella lib e vi copiamo le libreria tagsoup-1.2.jar, jdom.jar e jaxen-1.1.3.jar, per cui avremo le seguenti librerie nella cartella lib (non dimentichiamoci di includerle nel Build Path del nostro progetto: click col tasto destro -> Build Path -> Configure Build Path):

  • tagsoup-1.2.jar;
  • jdom.jar;
  • jaxen-1.1.3.jar.

Creiamo unaclasse Java TagSoupExample e scriviamo il codice seguente:


package it.appuntisoftware;

import java.net.URL;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;

public class TagSoupExample {

public static void main (String args[]){
URL url;
try {
    url = new URL("http://www.repubblica.it/");
    SAXBuilder builder = new SAXBuilder("org.ccil.cowan.tagsoup.Parser"); // build a JDOM tree from a SAX stream provided by tagsoup
    Document doc =  builder.build(url);
    XPath xpath =XPath.newInstance("/ns:html/ns:head/ns:title");
    xpath.addNamespace("ns","http://www.w3.org/1999/xhtml");
    String titolo = ((Element)xpath.selectSingleNode(doc)).getText();
    System.out.println("Title Sito Web: "+titolo);
    xpath =  XPath.newInstance( "/ns:html/ns:body/ns:div/ns:div/ns:div/ns:div/ns:div[@class='apertura articles']/ns:h1/ns:a");
    xpath.addNamespace( "ns", "http://www.w3.org/1999/xhtml");
    String titoloapertura = ((Element)xpath.selectSingleNode(doc)).getText();
    System.out.println("Titolo articolo di apertura: "+ titoloapertura);
    xpath =  XPath.newInstance( "/ns:html/ns:body/ns:div/ns:div/ns:div/ns:div/ns:div[@class='apertura articles']/ns:p");
    xpath.addNamespace( "ns", "http://www.w3.org/1999/xhtml");
    String contenutoapertura = ((Element)xpath.selectSingleNode(doc)).getText();
    System.out.println("Contenuto articolo di apertura: "+ contenutoapertura);
    } catch (Exception e) {
    e.printStackTrace();
    }
 }

}

In questo esempio abbiamo inserito come URL il sito di Repubblica, ovviamente possiamo sostituirlo con qualsiasi altro sito esistente nel web, ma in tal caso avremo una eccezione quando andremo ad esaminare i due path successivi al primo (che dovrebbe funzionare bene con qualsiasi sito visto che recupera il tag title contenuto all’interno dell’head del sito stesso), in quanto essi sono specifici del sito, infatti la Repubblica inserisce il suo articolo di punta (lo chiama articolo di apertura) all’interno di un div con l’attributo class valorizzato a ‘apertura articles’.

All’interno di questo div vi è poi il tag <h1> che rappresenta il link all’articolo ed il tag <p> con la descrizione dell’articolo.

La sintassi XPath è piuttosto semplice: data una rappresentazione ad albero del nostro documento, non resta che dare il percorso dove andare a recuperare il nodo secondo una sintassi del tipo “/radice/genitore/figlio/”. Nel caso di un nodo  in cui vi siano più figli, possiamo selezionare il ramo su cui procedere andando a specificare l’attributo del figlio con la seguente sintassi: “/nodofiglio[@nomeattributo=’valoreattributo’].

Infine ogni nome del nodo è preceduto dal suo namespace, nel nostro caso “ns” che è valorizzato con “http://www.w3.org/1999/xhtml”.

1 Stella2 Stelle3 Stelle4 Stelle5 Stelle (Nessun voto ancora)
Loading...
You can leave a response, or trackback from your own site.

Leave a Reply

*