CERCA SITEMAP FEED RSS 1280
Ultimo aggiornamento: 30 Agosto 2009

Document Object Model

A differenza di un parser SAX che fornisce un’interfaccia event-based per il parsing di documenti XML, un parser DOM (Document Object Model) fornisce un modello ad oggetti rappresentativo del documento XML.
In particolare il DOM fornisce una struttura ad albero in cui i singoli nodi sono rappresentativi degli elementi presenti all’interno del documento XML: tag, attributi e sezioni CDATA.
Document Object Model
Un semplice documento xml e la sua rappresentazione DOM: come si può notare la rappresentazione ad albero prevede un nodo per ogni tag del documento e per ogni nodo tanti nodi-figlio quanti sono i tag nidificati all’interno dello stesso.
Le classi coinvolte nell’elaborazione mediante DOM sono contenute nei seguenti package:
  • javax.xml.parsers contiene le classi DocumentBuilder e DocumentBuilderFactory che permettono di creare un parser DOM ed utilizzare quest’ultimo per ottenere una struttura ad albero rappresentativa del contenuto di un documento XML
  • org.w3c.dom definisce tutte le interfacce coinvolte nella rappresentazione di un documento XML
  • javax.xml.transform per effettuare trasformazioni sul documento XML mediante XSLT
A differenza di un parser SAX, il DOM permette inoltre di poter modificare la struttura del documento ed addirittura crearne di nuovi a partire da zero.

Il DOM è adatto per:
  • costruire documenti xml ben formati e validi
  • manipolare documenti xml
ma ha anche alcuni svantaggi:
  • richiede un eccessivo carico computazione (occorre mantenere in memoria la struttura dati ad albero rappresentativa del documento xml)
  • non è adatto per operazioni di filtraggio e di lettura (per le quali invece è preferibile usare un parser SAX)

Creazione del parser DOM

La creazione di un parser DOM (che in java è rappresentato dalla classe DocumentBuilder) avviene sfruttando il metodo newDocumentBuilder() della classe DocumentBuilderFactory in maniera del tutto analoga a quanto visto per la creazione di un parser SAX.

Prima di creare un DocumentBuilder è opportuno configurare il DocumentBuilderFactory in base alle nostre esigenze:
  • specificando se vogliamo creare un parser validante setValidating(boolean validating)
  • indicando l’eventuale schema del documento XML setSchema(Schema schema)
  • specificando se ignorare i commenti presenti nel documento XML o meno setIgnoringComments(boolean ignoring)
A questo punto invocando il metodo newDocumentBuilder() si ottiene un’istanza di un parser DOM.
...

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();

...
Poiché nel corso del parsing di un documento XML potrebbero verificarsi degli errori la classe DocumentBuilder consente di poter registrare un gestore di errori (ErrorHandler) in maniera del tutto analoga a quando avviene per i parser SAX (ciò è facilitato dal fatto che generalmente un parser DOM sfrutta il lavoro di un parser SAX).
Il metodo setErrorHandler(ErrorHandler errorHandler) della classe DocumentBuilder permette quindi di poter specificare il gestore degli eventi-errore così come il metodo setEntityResolver(EntityResolver entityResolver) permette di registrare un gestore di entità esterne al documento XML preso in esame.
A questo punto se si vuole creare un documento XML ex-novo occorre invocare il metodo newDocument() se invece si vuole ottenere il modello DOM rappresentativo di un documento XML esistente occorre invocare il metodo parse(InputSource is) indicando il riferimento al documento XML.
In entrambi i casi otterremo un oggetto Document (vuoto nel primo caso) che costituisce la radice del documento XML e contiene i metodi necessari alla creazione di nuovi elementi.

L'interfaccia Document

Oltre ad essere rappresentativa dell’intero documento XML l’interfaccia Document contiene metodi per l’accesso diretto agli elementi costitutivi del documento e per la creazione di nuovi.
Prima di descrivere tali metodi è opportuno precisare che ogni elemento del documento XML costituisce nella rappresentazione DOM un nodo dell’albero ed è quindi rappresentato da un oggetto di tipo Node.

L’interfaccia Node offre metodi per:
  • il recupero di informazioni: getNodeName(), getNodeType(), getNodeValue(), getTextContent(), getAttributes() ...
  • la modifica di informazioni: setNodeValue(String value), setTextContent(String textContent) ...
  • la navigazione dell’albero: getChildNodes(), getFirstChild(), getLastChild(), getNextSibling(), getParentNode() ...
  • la modifica della struttura dell’albero: appendChild(Node child), removeChild(Node child), replaceChild(Node newChild, Node oldChild) ...
Un nodo (Node) dell’albero può essere di diversi tipi:
  • un attributo (interfaccia Attr)
  • una sezione CDATA (interfaccia CDATASection)
  • un commento (interfaccia Comment)
  • un elemento (interfaccia Element)
  • un’entità (interfaccia Entity)
  • una notazione (interfaccia Notation)
  • una Processing Instruction (interfaccia Processinginstruction)
  • un nodo testo (interfaccia Text)
Ciascuna di queste interfacce estende le funzionalità offerte dall’interfaccia Node aggiungendone di nuove.

Anche il Document è un Node e definisce metodi per l’accesso diretto ai nodi dell’albero come
  • getElementById(Stringi d)
  • getElementsByTagName(String tagname)
e metodi per la creazione di nuovi elementi come
  • createElement(String tagname) crea un oggetto di tipo Element
  • createAttribute(String name) crea un oggetto di tipo Attr
  • createComment(String comment) crea un oggetto di tipo Comment
  • createTextNode(String textvalue) crea un oggetto di tipo Text
  • createCDATASection(String data) crea un oggetto di tipo CDATASection
Così supponendo di voler creare ex-novo un documento XML di questo tipo:
<primotag>
  <secondotag>
    valore testo
  </secondotag>
</primotag>
dovremmo scrivere:
...

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
Element primotag = document.createElement("primotag");
document.appendChild(primotag);
Element secondotag = document.createElement("secondotag");
primotag.appendChild(secondotag);
Text nodotesto = document.createTextNode("valore testo");
secondotag.appendChild(nodotesto);

...
Supponendo invece di aver memorizzato il documento XML all’interno di un file e di voler accedere al contenuto del nodo Text figlio del nodo Element "secondo tag" (e quindi recuperare la stringa "valore testo") potremmo scrivere:
...

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(new File("prova.xml"));

Element primotag = (Element)document.getFirstChild();
Element secondotag = (Element)primotag.getFirstChild();
Text nodotesto = (Text)secondotag.getFirstChild();

String valoretesto = nodotesto.getNodeValue();

...

Le trasformazioni

Analogamente a quanto visto per il parsing mediante SAX è possibile applicare delle trasformazioni XSLT anche ad un documento XML rappresentato mediante DOM mediante l’utilizzo della 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 di cui si conosce la rappresentazione DOM mediante XSLT:
...

Document documentoxml;

...

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

DOMSource domSource = new DOMSource(documentoxml);

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

StreamResult outputstream = new StreamResult(output);

transformer.transform(domSource, outputstream);

...