CERCA SITEMAP FEED RSS 1280
Ultimo aggiornamento: 30 Agosto 2009

Simple API for XML

Un parser XML permette ad un’applicazione di accedere al contenuto di un documento XML.

Generalmente i parser XML si dividono in:
  • non validanti che si limitano a controllare se un documento XML è ben formato (cioè che ogni elemento sia racchiuso fra due tag)
  • validanti che oltre a controllare se un documento XML è ben formato controllano anche se un documento XML sia ben formato ovvero che rispetti le regole definite nella Document Type Definition (DTD).
SAX (Simple API for XML) fornisce un’interfaccia event-based per il pasring di documenti XML; il documento viene scandito sequenzialmente e viene generato un evento quando:
  • inizia e finisce un documento
  • inizia e finisce un elemento
  • la presenza del contenuto di un elemento
  • la presenza di Processing Instruction
  • errori di sintassi XML di vario genere
Per ognuno di questi eventi occorre pertanto specificare le azioni da compiere: ovvero definire dei gestori che operino in risposta agli eventi generati.
  • ContentHandler si occupa della gestione degli eventi relativi al contenuto logico del documento
  • DTDHandler si occupa della gestione degli eventi relativi al Document Type Definition
  • ErrorHandler si occupa della gestione degli eventi relativi agli errori
  • EntityResolver gestisce i riferimenti ad entità esterne al documento XML
Un’applicazione generalmente instanzia un parser, provvede a registrare i necessari Handler presso il parser stesso ed avvia l’elaborazione del documento XML.
I vantaggi di un parser SAX rispetto ai parser object-oriented (come il DOM) sono:
  • la semplicità
  • la possibilità di poter trattare un sottoinsieme delle informazioni interrompendo il parsing del documento quando necessario.
  • la possibilità di poter costruire una propria struttura dati a partire delle informazioni ricavate da un documento XML (a differenza di DOM che genera una struttura di dati ad albero di tutto il documento XML)
  • la possibilità di poter analizzare documenti di qualsiasi dimensione (in quando non richiede grandi risorse di memoria)
Di contro gli svantaggi sono:
  • l’impossibilità di accedere casualmente al documento (è consentito soltanto un accesso sequenziale)
  • l’impossibilità di modificare il documento XML (è un sistema di sola lettura)
  • la difficoltà di implementazione di interrogazioni complesse al documento
Tipicamente SAX si utilizza quando:
  • Si stanno cercando pochi elementi
  • La struttura del documento non è importante per l’applicazione
  • Non si stanno cercando elementi dipendenti dal contesto
  • La risorsa memoria è critica

Creazione del parser SAX

La classe SAXParserFactory permette di creare e configurare parser SAX.

E’ possibile ottenere un’istanza di tale classe nel seguente modo:
  SAXParserFactory.newInstance();
Prima di ottenere il parser è opportuno stabilire se si vuole procedere anche ad una validazione del documento XML da processare.
Il metodo setValidating(boolean validating) serve appunto ad indicare al SAXParserFactory di generare parser validanti o meno: è possibile specificare lo schema mediante il quale effettuare la validazione del documento mediante il metodo setSchema(Schema schema).
L’oggetto Schema appartiene al package javax.xml.validation e viene generalmente ottenuto sfruttando il metodo newSchema(File schema) della classe SchemaFactory (ma è possibile generare oggetti Schema anche da un url mediante il metodo newSchema(URL schema)).
E’ possibile anche specificare il gestore degli errori (ErrorHandler) che potrebbero verificarsi a seguito della creazione di uno Schema se questo non è conforme alle specifiche del W3C mediante il metodo setErrorHandler(ErrorHandler errorHandler).
Una volta creato lo schema è possibile configurare il SAXParserFactory e quindi ottenere un oggetto SAXParser mediante il metodo newSAXParser()
Ecco un esempio completo:
...

SAXParserFactory istanzafactory = SAXParserFactory.newInstance();
SAXParser parser = istanzafactory.newSAXParser();

...
Un SAXParser ingloba al suo interno un oggetto XMLReader che costituisce appunto un’interfaccia per la lettura di documenti XML e per la registrazione dei gestori degli eventi generati.

In particolare:
  • il metodo setContentHandler(ContentHandler contentHandler) permette di impostare il gestore degli eventi relativi al contenuto logico del documento
  • il metodo setDTDHandler(DTDHandler dtdHandler) permette di impostare il gestore degli eventi relativi al Document Type Definition
  • setErrorHandler(ErrorHandler errorHandler) permette di impostare il gestore degli eventi relativi agli errori che si verificano in fase di processamento del documento XML
  • setEntityResolver(EntityResolver entityResolver) permette di impostare il gestore degli eventi relativi alle entità esterne al documento XML
il metodo parse(InputSource source) invece avvia il parsing del documento XML identificato dall’InputSource passato come parametro.
...

try
{
   SAXParserFactory istanzafactory = SAXParserFactory.newInstance();
   istanzafactory.setValidating(true);
   SAXParser parser = istanzafactory.newSAXParser();
   lettorexml = parser.getXMLReader();
   lettorexml.setContentHandler(new mioContentHandler());
   lettorexml.setErrorHandler(new mioErrorHandler()););

   ...

}
catch(Exception ecc)
{
   ...
}

...
Recuperare l’XMLReader dal SAXParser e quindi definire tutti i gestori degli eventi risulta essere un’operazione piuttosto onerosa in quanto occorre implementare tutte le interfacce degli Handler; per questa ragione l’oggetto SAXParser permette di avviare il parsing di un documento XML specificando un oggetto che estende il tipo DefaultHandler (appartenente al package org.xml.sax.helpers) e naturalmente il documento XML da processare.
Il DefaultHandler infatti implementa le quattro interfacce per la gestione degli eventi generati durante il parsing del documento pertanto sarà sufficiente estenderlo, ridefinire i metodi di nostro interesse e quindi invocare il parsing del documento: il tutto senza accedere all’oggetto XMLReader e senza implementare le singole interfacce.

Gestione degli eventi

La trattazione delle Simple API for XML non può concludersi senza la trattazione dei gestori degli eventi (Handler).

L’interfaccia ContentHandler si occupa della gestione degli eventi relativi al contenuto del documento mediante i seguenti metodi:
  • characters(char[] ch, int start, int length) riceve notifica della presenza di una sezione CDATA
  • endDocument() viene invocato quando si rggiunge la fine del documento XML
  • endElement(String uri, String localName, String qName) riceve la notifica della fine di un elemento (viene quindi incontrato il tag di chiusura)
  • ignorableWhitespace(char[] ch, int start, int length) riceve notifica della presenza di spazi bianchi nel documento XML che possono essere ignorati
  • processingInstruction(String target, String data) riceve notifica della presenza di una Processing Instruction
  • skippedEntity(String name) riceve notifica di un’entità che viene saltata
  • startDocument() viene invocato quando inizia il documento XML
  • startElement(String uri, String localName, String qName, Attributes atts) viene invocato quando inizia un elemento (viene incontrato il tag di apertura)
Il seguente esempio rappresenta un ContentHandler che il documento XML in base alle notifiche degli eventi che vengono invocati di volta in volta durante il parsing.
public MioContentHandler implements ContentHandler
{

   public void characters(char[] ch, int start, int length)
   {
      String s = new String(ch,start,length);
      System.out.println(s);
   }

   public void endDocument()
   {
   }

   public void endElement(String uri, String localName, String qName)
   {
      System.out.println("</"+qName+">");
   }

   public void endPrefixMapping(String prefix)
   {
   }

   public void ignorableWhitespace(char[] ch, int start, int length)
   {
   }

   public void processingInstruction(String target, String data)
   {
   }

   public void setDocumentLocator(Locator locator)
   {
   }

   public void skippedEntity(String name)
   {
   }

   public void startDocument()
   {
   }

   public void startElement(String uri, String localName, String qName, Attributes atts)
   {
      System.out.print("<"+qName);
      for (int i=0;i<atts.getLength();i++)
      System.out.print(" "+atts.getQName(i)+"= "+atts.getValue(i));
      System.out.println(">");
   }

   public void startPrefixMapping(String prefix, String uri)
   {
   }

}
L’interfaccia ErrorHandler gestisce gli eventi relativi agli errori che potrebbero presentarsi durante il parsing di un documento XML:
  • error(SAXParseException exception) riceve notifica di un errore recuperabile
  • fatalError(SAXParseException exception) riceve notifica di un errore non recuperabile
  • warning(SAXParseException exception) riceve notifica di un avvertimento
public class MioErrorHandler implements ErrorHandler
{
   public void error(SAXParseException exception)
   {
      System.out.println("errore :"+exception.getMessage());
   }

   public void fatalError(SAXParseException exception)
   {
      System.out.println("errore fatale:"+exception.getMessage());
   }

   public void warning(SAXParseException exception)
   {
      System.out.println("warning :"+exception.getMessage());
   }

}
L’interfaccia ResolveEntity si occupa della gestione delle entità esterne mediante il metodo resolveEntity(String publicId, String systemId) che viene invocato quando viene incontrata un’entità esterna nel documento.

Infine l’interfaccia DTDHandler contiene i metodi:
  • notationDecl(String name, String publicId, String systemId) gestisce l’evento di dichiarazione di una notazione
  • unparsedEntityDecl(String name, String publicId, String systemId, String notationName) gestisce l’evento di dichiarazione di un’entità non analizzata

Le trasformazioni

Per effettuare trasformazioni al documento XML mediante XSLT (eXtensible Stylesheet Language Transformations) al fine di ottenerne un altro (ad esempio un XHTML o un WML) si utilizza la classe Transformer del package javax.xml.transform.
La classe Trasformer viene creata a partire da un TrasformerFactory mediante il metodo newTransformer(Source source) dove source indica il riferimento al documento XSLT.
...

StreamSource xlstStreamSource = new StreamSource(new File(filexsl));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xlstStreamSource);

...
Una volta ottenuto l’oggetto Transformer è possibile effettuare la trasformazione di un documento XML mediante il metodo transform(Source xmlSource, Result outputTarget) indicando il documento XML sorgente ed il riferimento al risultato.

Il seguente esempio mostra come ottenere una trasformazione di un documento XML mediante XSLT:
...

StreamSource xsltStream = new StreamSource(new File(filexsl));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(xsltStream);

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(URLDocumentoXML.openStream()));
SAXSource saxSource = new SAXSource(new InputSource(bufferedReader));

File output = new File(outputFileName);
if(output.exists())
output.delete();

StreamResult outputstream = new StreamResult(output);

transformer.transform(saxSource, outputstream);

...