XML
è una tecnologia avviata a un utilizzo pervasivo negli ambiti di
Web publishing e applicazioni business to business. Come ben sappiamo Java
è il linguaggio ideale per questo tipo di applicazioni, grazie alle
sue caratteristiche di portabilità ed estendibilità, ed è
quindi naturale un punto di incontro delle due tecnologie.
XML e tecnologie
correlate
In
questo paragrafo vedremo gli aspetti principali di questa tecnologia e
nei capitoli successivi riprenderemo i concetti e gli esempi presentati
per vedere qualche esempio di programmazione Java. Si vuole precisare che
questo paragrafo non vuole essere un completo tutorial di XML ma un semplice
punto di partenza.
Cos'è XML
XML
(eXtensible Markup Language) è un meta-linguaggio per definire nuovi
linguaggi basati su tag. Per questo aspetto XML è molto simile a
HTML, anch'esso basato su tag, ma c'è una differenza fondamentale:
XML è una notazione per definire linguaggi mentre HTML è
un particolare linguaggio.
I
punti chiave di XML sono
-
separazione
del contenuto dalla rappresentazione dei dati: un documento XML definisce
il contenuto informativo e non contiene alcuna informazione
relativa alla formattazione dei dati;
-
definizione
di un formato standard: XML è uno standard del W3C e quindi un documento
XML può essere elaborato da qualsiasi parser o tool conforme
allo standard.
Vediamo
un semplice esempio di file XML.
<?xml
version="1.0"?>
<books>
<book>
<author>P.K. Dick</author>
<title>Ubik</title>
</book>
<book>
<author>William Gibson</author>
<title>Neuromante</title>
</book>
<book>
<author>Franz Kafka</author>
<title>Il processo</title>
</book>
</books>
Il
documento precedente definisce una lista di libri con i corrispondenti
autori e titoli. La struttura gerarchica di un documento XML, con l'annidamento
degli elementi, permette una naturale rappresentazione di una collezione
di libri e delle informazioni associate ad un singolo libro. I tag utilizzati
(books, book, author e title) sono completamente inventati,
hanno
esclusivamente significato informativo e non contengono alcuna informazione
di rendering. Ad esempio leggendo il contenuto di un elemento author possiamo
risalire all'autore del libro in esame ma non sappiamo nemmeno se il documento
verrà visualizzato come pagina HTML o altro.
Struttura di un
documento XML
Così
come un documento HTML deve essere redatto secondo alcune regole sintattiche
ben precise perchè sia visualizzabile
da
un browser anche un documento XML deve rispettare ben precise regole strutturali;
in particolare
-
ogni tag
aperto deve essere chiuso;
-
i tag
non devono essere sovrapposti;
-
i valori
degli attributi devono essere racchiusi fra "";
-
i caratteri
'<', '>' e '"' nel testo di un file XML devono essere rappresentati
dai caratteri speciali '<', '>' e '"'.
I documenti
XML che rispettano le regole precedenti vengono detti ben formati (well-formed).
Oltre a poter definire
documenti
ben formati è possibile specificare la particolare struttura di
un file XML, ad esempio per garantire che il tag
author
sia compreso all'interno del tag book. A tal proposito il W3C ha definito
due modalità
-
DTD (Document
Type Definition): si tratta di un particolare documento che definisce i
tag utilizzabili in un documento XML e anche la loro
struttura. Il seguente esempio mostra un DTD per il linguaggio XML di definizione
di libri usato nel documento visto in precedenza
<!ELEMENT books (book)+>
<!ELEMENT book (author,title)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT title (#PCDATA)>
Il
DTD dichiara che il tag books contiene un numero non precisato di elementi
book; questo a sua volta contiene i tag author e title che contengono solo
caratteri.
-
Schema:
rappresentano un modo alternativo ai DTD per esprimere la struttura di
un documento. Il principale vantaggio degli schema consiste nel fatto che
vengono essi stessi descritti in XML! Vediamo ad esempio lo schema per
la definizione del documento XML precedente
<xsd:schema xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<xsd:element name="books" type="BooksType"/>
<xsd:complexType name="BookType">
<xsd:element name="book" type="BookType" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:complexType>
<xsd:element name="book" type="BookType"/>
<xsd:complexType name="BookType">
<xsd:element name="author" type="xsd:string"/>
<xsd:element name="title" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
Il
documento precedente sarà contenuto in un file .xsd (XML Schema
Definition).
L'elemento
principale è schema che a sua volta contiene altri elementi
-
element:
definisce un elemento del documento XML e le informazioni ad esso associato
(numero di occorrenze,...);
-
complexType:
definisce un tipo composto, ovvero un elemento che contiene a sua volta
altri elementi e avere attributi.
Maggiori
informazioni sugli schema si possono trovare in http://www.w3.org.
I
parser XML possono essere non validanti oppure validanti. Mentre i primi
verificano che il documento ricevuto in input sia ben formato e mentre
i parser validanti verificano anche la struttura del documento basandosi
sul corrispondente DTD o schema. Come vedremo più in dettaglio nel
seguito i parser si distinguono anche in parser SAX (Simple API for XML)
e DOM (Document Object Model). I parser SAX mettono a disposizione una
API event-driven per la gestione dei documenti mentre i parser DOM restituiscono
il documento XML con una struttura ad albero.
XSL
XSL
(per il momento tralascio la spiegazione dell'acronimo) è un linguaggio,
sempre definito dal W3C, per trasformare un documento XML in un diverso
documento XML. XSL è particolarmente potente anche perchè
viene definito in XML e ha tutte le caratteristiche di estendibilità
tipiche dei documenti XML. XSL è composto da
-
XSLT:
un linguaggio dichiarativo per trasformare i documenti XML;
-
formatting
objects: questa parte di XSL relativa alla formattazione dei documenti
non è ancora standard e la prima implementazione disponibile è
FOP (Formatting Object Processor) dell'Apache XML Group che permette di
ottenere documenti PDF.
L'utilizzo
principale di XSL consiste comunque nel trasformare un documento XML in
un documento diverso (HTML, PDF, ...) che sia quindi visualizzabile con
i corrispondenti viewer (browser Web). XSL sta infatti per XML Stylesheet
Language.
Nel
seguito dell'articolo vedremo alcuni esempi di trasformazioni di documenti
XML via XSL. E' comunque importante sottolineare ancora che XSLT permette
di trasformare un documento XML in un diverso documento XML, ad esempio
per eseguire alcune elaborazioni applicative; l'utilizzo di XSLT per ottenere
pagine HTML è cioè solo un caso particolare anche se molto
importante.
Tool XML per Java
Negli
ultimi mesi si è avuto un grosso interesse verso XML da parte dei
principali produttori di software come Microsoft, Sun, IBM e Oracle. In
particolare nel mondo Java si è visto un particolare fermento per
questa nuova tecnologia: per averne una prova è sufficiente visitare
i siti di IBM e Oracle.
Java
è un ottimo linguaggio per programmare applicazioni XML in quanto
-
Il binding
Java del Document Object Model fornisce uno strumento standard e un punto
di riferimento per gli sviluppatori;
-
Le caratteristiche
object oriented di Java permettono di gestire in maniera naturale la struttura
gerarchica dei documenti XML;
-
XML permette
la trasmissione di dati su Internet separando il contenuto dalla presentazione
di questi; allo stesso modo
Java permette
di scrivere applicazioni indipendenti dalla piattaforma. In questo modo
è possibile combinare la portabilità dei dati e la portabilità
del codice ottenendo applicazioni estremamente potenti.
Nel
seguito del paragrafo vedremo una rassegna di alcuni strumenti basati su
tecnologia XML per Java.
Parser
-
XML4J:
La tecnologia alla base del parser XML di IBM è stata donata all'Apache
Group per lo sviluppo del parser Xerces. L'ultima versione di XML4J attualmente
disponibile, la 3.0.1, è derivata dalla release 1.0.3 di Xerces.
-
Xerces:
è un parser sviluppato dal team di Apache all'interno dell'Apache
XML Project. E' basato sui sorgenti di XML4J, implementa DOM (livello
1 e 2) e SAX (versione 2) e ha un supporto preliminare per gli schema XML.
E' disponibile inoltre una versione in C++ con i wrapper Perl
e COM.
-
XP: XP
è un parser non validante sviluppato da James Clark (http://www.jclark.com)conforme
alle specifiche 1.0 di XML. Oltre a una normale API ad alto
livello fornisce anche una API a basso livello er viluppare nuovi
parser. XP è sviluppato principalmente per ottenere
alte prestazioni.
XSL
-
XT è
sviluppato da James Clark (http://www.jclark.com). Ha varie caratteristiche
interessanti come l'estendibilità attraverso codice Java e la possibilità
di generare diversi file di output a fronte di un unico input. XT permette
inoltre di generare output non XML e può
essere usato come servlet.
-
Xalan
è un engine XSL che implementa la versione 1.0 di XSLT e la versione
1.0 di XPath. E' sviluppato dall'Apache
-
XML Group
e si tratta di un prodotto derivato da LotusXSL. Per poter eseguire il
parsing dei documenti XML da trasformare e degli stylesheet
XSL Xalan usa di default un parser XML con un modello a oggetti 'proprietario',
il DTM (Document Table Model). L'utilizzo di DOM
può infatti penalizzare le prestazioni in quanto si deve creare
un oggetto Java per ogni elemento del documento. Il DTM utilizza
invece degli array di interi. Xalan può comunque essere
configurato per utilizzare il parser Xerces. L'input può essere
un file, uno stream, un documento DOM o uno stream di eventi SAX
e allo stesso modo l'output può essere un file, un documento DOM,
una serie di eventi SAX o uno stream. Xalan può essere
eseguito dalla linea di comando, da un applet o anche in un servlet. Xalan
è inoltre estendibile attraverso appositi elementi
e funzioni incapsulati in un namespace XML. Sono supportati diversi linguaggi
di scripting mediante l'architettura BSF (Bean Scripting
Framework). Una estensione interessante di Xalan consiste nella
possibilità di generare diversi documenti di output a partire dallo
stesso XML iniziale.
-
LotusXSL
fa parte dei progetti IBM alphaWorks. Da novembre 1999 il progetto è
stato passato all'Apache Group per lo sviluppo di Xalan. La release
di LotusXSL include una serie di classi wrapper che permettono di usare
la API LotusXSL pre-Xalan che a sua volta richiama la API Xalan.
Le nuove funzionalità fanno comunuqe parte della API
Xalan.
Web
publishing
Cocoon
è un framework per il web-publishing completamente basato su Java
e le tecnologie XML ( comprendendo quindi XSL e DOM). L'idea di base di
Cocoon è quella di separare le fasi dello sviluppo di contenuti
Web:
-
creazione
del documento XML: nella vision Cocoon il documento XML viene prodotto
in genere da utenti umani che conoscono dei contenuti del documenti ma
ai quali non si richiede alcuna conoscenza relativa all'elaborazione del
contenuto;
-
elaborazione
del documento XML: una delle peculiarità di Cocoon consiste nella
separazione fra creazione del documento XML e la sua elaborazione applicativa
(non si tratta quindi di rendering). A tal proposito si utilizza il termine
logicsheet e Cocoon propone XSP (eXtensible Server Pages), un linguaggio
XML per descrivere la logica applicativa per elaborare i documenti XML;
-
rendering
XSL: per la visualizzazione del documento si applica uno stylesheet XSL
e si formatta il documento nel formato richiesto (XML, HTML, PDF, ...).
L'architettura
di Cocoon è fortemente basata sulle caratteristiche di XSLT. Il
framework espone una API attraverso XML e un'interfaccia più sofisticata
in Java.
Cocoon
è inoltre in grado di distinguere il browser che ha originato la
richiesta e determinare quale stylesheet applicare al documento richiesto
in modo da ottenere un output adeguato per le capacità del browser.
Questa
breve rassegna si è limitata ai principali strumenti disponibili
per sviluppare applicazioni Java basate su XML.
Oltre
a questi è possibile trovarne altri come ad esempio, nel sito IBM,
vari tool visuali per l'editing dei documenti XML e XSL.
JAXP:
Java API for XML Parsing
JAXP
(API chiamata precedentemente Project X) vuole fornire al programmatore
i mattoni di base per realizzare applicazioni XML. Più che di applicazioni
si può parlare di un framework di sviluppo basato su servizi e applicazioni.
Le funzionalità di JAXP rappresentano il cosiddetto core per la
realizzazione di applicazioni XML in Java. Questo nucleo di base include
-
La possibilità
di utilizzare diversi parser (pluggability);
-
API per
il parsing (con eventuale validazione) dei documenti;
-
DOM API
per poter gestire un documento XML come una struttura ad albero;
Le
API precedentemente citate si triovano nel package com.sun.xml.*. Sulla
base degli elementi forniti da JAXP è possibile costruire dei servizi,
ovvero moduli che forniscono funzionalità troppo specializzate per
far parte della core API. Ad esempio un modulo per l'elaborazione dei documenti
in XSL potrebbe essere utile in vari contesti ma non in tutti.
Utilizzando
la core API ed eventualmente servizi addizionali si possono sviluppare
applicazioni complete basate su XML
come
Web-publishing e transazioni per l'e-commerce business-to-business.
Veniamo
ora ad analizzare la API che a un primo livello si può suddividere
in API per il parsing, definita nel package javax.xml.parsers, e API per
il DOM. Il DOM, Document Object Model, è una recommendation del
W3C che definisce una API per l'elaborazione dei documenti XML; tale API
è definita nel package org.w3c.dom.
La
API per il parsing fornisce le classi e le interfacce per l'elaborazione
dei documenti XML. Vengono supportati i parser DOM e SAX in modo pluggable,
ovvero è possibile utilizzare parser di terzi all'interno delle
proprie applicazioni continuando ad utilizzare la API JAXP. Ad esempio
la classe DocumentBuilder permette di ottenere un documento DOM a partire
da un documento XML. E' importante osservare che un oggetto di classe DocumentBuilder
può fare riferimento a diverse implementazioni.
Il
codice seguente mostra come eseguire il parsing del documento XML e ottenere
un documento DOM, rappresentato dall'interfaccia Document.
DocumentBuilderFactory
dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder
db = dbf.newDocumentBuilder();
InputStream
is = new FileInputStream("test.xml");
Document
doc = db.parse(is);
doc.getDocumentElement().normalize();
A questo
punto è possibile navigare la struttura ad albero del documento:
Node
book = doc.getDocumentElement();
NodeList
book_list = doc.getElementsByTagName("book"),
book_items;
for(int
i=0; i<book_list.getLength(); i++) {
book_items = book_list.item(i).getChildNodes();
for(int j=0; j<book_items.getLength(); j++) {
System.out.println(
book_items.item(j).getFirstChild().getNodeValue());
}
}
E'
importante considerare che il codice precedente è completamente
indipendente dalla particolare implementazione del
parser
DOM utilizzato.
JAXP
fornisce anche il supporto per la API SAX attraverso la classe SAXParser.
SAX (Simple API for XML) è un'interfaccia event-driven standard
definita dal W3C per l'elaborazione dei documenti XML. Il supporto per
la API SAX si trova nel package org.xml.sax mentre il package org.xml.sax.helpers
fornisce alcune classi accessorie. A differenza di DOM, che crea la struttura
ad albero del documento residente in memoria, i parser SAX generano eventi
che vengono intercettati da un apposito handler fornito dallo sviluppatore.
Più precisamente il parser SAX legge il documento XML e genera eventi
corrispondenti alla struttura del documento. Lo sviluppatore deve definire
un handler, che implementa l'interfaccia org.xml.sax.DocumentHandler, per
definire i metodi callback che vengono invocati in corrispondenza degli
eventi. Per semplificare il compito dei programmatori viene fornita la
classe org.xml.sax.HandlerBase che implementa tutti
i
metodi di DocumentHandler come no-operation; i metodi sono cioè
vuoti. In questo modo per definire un proprio handler è sufficiente
estendere HandlerBase e ridefinire solo i metodi necessari.
Vediamo
ora come istanziare il parser SAX ed eseguire il parsing di un documento.
SAXParserFactory
spf = SAXParserFactory.newInstance();
spf.setValidating(true);
SAXParser
sp = spf.newSAXParser();
Parser
parser = sp.getParser();
parser.setDocumentHandler(
new MyDocumentHandler() );
parser.setErrorHandler(
new MyErrorHandler() );
String
file_name = "file:" + new File("test.xml").getAbsolutePath();
parser.parse(
new InputSource(file_name) );
L'input
del parser è un'istanza della classe org.xml.sax.InputSource che
incapsula appunto la sorgente dati di un documento
XML
in questo caso specificata attraverso un system ID, cioè un URI
a un file. La classe MyDocumentHandler definisce un
handler
per il tipo di documento in esame. Supponiamo di voler contare il numero
di libri di P.K. Dick citati nel documento
public
class MyDocumentHandler extends HandlerBase {
private int counter;
private boolean is_author;
public MyDocumentHandler() {
super();
counter = 0;
is_author = false;
}
public void characters(char[] ch, int start, int length) throws SAXException
{
if (is_author) {
String data = new String(ch, start, length);
if (data.equalsIgnoreCase("P.K. Dick")) {
counter++;
}
}
}
public void startElement(String name, AttributeList attributes) throws
SAXException {
if (name.equals("author")) {
is_author = true;
}
}
public void endElement(String name) throws SAXException {
if (name.equals("author")) {
is_author = false;
}
}
public void endDocument() {
System.out.println("Found " + counter + " P.K. Dick's books");
}
}
Analogamente
anche per la gestione degli errori si prevede un apposito handler che implementi
l'interfaccia org.xml.sax.ErrorHandler; tale interfaccia definisce i seguenti
metodi
warning(): segnalazione di un warning;
error(): errore recuperabile;
fatalError(): errore non recuperabile;
La
classe HandlerBase implementa comunque anche i metodi di ErrorHandler e
può essere estesa per definire un gestore
di
errori custom. Il parser può quindi essere configurato per segnalare
gli errori non con eccezioni al programma client ma
attraverso
l'interfaccia ErrorHandler. La nostra implementazione di esempio ridefinisce
i metodi error e warning.
public
class MyErrorHandler extends HandlerBase {
public
void error(SAXParseException e) throw SAXException {
throw e;
}
public
void warning(SAXParseException e) throw SAXException{
System.out.println(e.getMessage());
}
}
Un esempio completo
Vediamo
ora un esempio completo di utilizzo di XML in una ipotetica applicazione
per la gestione di libri. Dovremo innanzitutto realizzare degli oggetti
applicativi che incapsulano le informazioni relative a un libro (nel nostro
semplice caso ci limitiamo ad autore e titolo). Un requisito della nostra
applicazione è che tali oggetti possano essere istanziati anche
a partire da un file XML, o meglio da un frammento di file XML visto che
un file contiene informazioni relative a più libri.
Segue
ora il codice della classe Book che implementa i requisiti precedenti
import
org.w3c.dom.Element;
public
class Book {
private String author;
private String title;
// Default constructor.
public Book() {}
// Build a Book object with the specified author and title.
public Book(String author, String title) {
this.author = author;
this.title = title;
}
// Build a Book object from a DOM element.
public Book(Element element) {
author = element.getElementsByTagName
("author").item(0).getFirstChild().getNodeValue();
title = element.getElementsByTagName
("title").item(0).getFirstChild().getNodeValue();
}
// get methods
public String getAuthor() {
return author;
}
public String getTitle() {
return title;
}
// set methods
public void setAuthor(String author) {
this.author = author;
}
public void setTitle(String title) {
this.title = title;
}
}
Soffermiamoci
sul costruttore Book(Element element). Esso riceve in ingresso un elemento
DOM rappresentato dall'interfaccia Element. Si usa quindi il metodo getElementsByTagName()
in modo da reperire una lista di nodi il cui tag
abbia
il nome specificato. Il metodo ritorna un'implementazione dell'interfaccia
NodeList che rappresenta una lista di nodi del documento. In questo caso
contiene un solo elemento; si accede quindi all'informazione associata
al nodo mediante la
catena
di chiamate .item(0).getFirstChild().getNodeValue(). La classe DOMTest
mostra come caricare una collezione di oggetti Book con le informazioni
contenute nel file XML specificato
import
java.io.*;
import
java.util.*;
import
javax.xml.parsers.*;
import
org.w3c.dom.*;
import
org.xml.sax.*;
import
Book;
public
class DOMTest {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("Usage: java DOMTest xmlfilename");
System.exit(1);
}
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new File(args[0]));
NodeList nl = doc.getElementsByTagName("book");
Element e;
Collection c = new Vector();
// fill collection with book objects
for (int i=0; i<nl.getLength(); i++) {
e = (Element)nl.item(i);
c.add( new Book(e) );
}
// print out collection content
Iterator i = c.iterator();
Book book;
while (i.hasNext()) {
book = (Book)i.next();
System.out.println("Author: " + book.getAuthor() +
" - title: " + book.getTitle());
}
}
catch (IOException ioe) {
System.err.println("Input/Output error: " + ioe.getMessage());
System.exit(1);
}
catch (SAXParseException spe) {
System.err.println("Parsing exception for entity " + spe.getPublicId()
+
" at line: " + spe.getLineNumber() +
" column: " + spe.getColumnNumber());
System.exit(1);
}
catch (SAXException se) {
System.err.println("General SAX exception: " + se.getMessage());
System.exit(1);
}
catch (ParserConfigurationException pce) {
System.err.println("General SAX exception: " + pce.getMessage());
System.exit(1);
}
catch (FactoryConfigurationError fce) {
System.err.println("Configuration error: " + fce.getMessage());
System.exit(1);
}
}
}
Innanzitutto
si crea un parser XML per ottenere un documento DOM a partire dal file
XML fornito come argomento alla linea di comando. Si ottiene quindi la
lista di nodi "book" contenuti nel documento e per ognuno di essi si crea
un oggetto
Book
da inserire in una collezione di oggetti. Al termine di questa elaborazione
si ottiene una collezione pronta per eventuali elaborazioni. Nel nostro
esempio si itera semplicemente la collezione per visualizzarne il
contenuto. La gestione degli errori mostra alcuni aspetti interessanti:
in particolare nel caso si verifichi un errore di parsing questo
viene segnalato dall'eccezione SAXParseException che permette di ottenere
precise informazioni relative alla posizione in cui si è verificato
l'errore nel file XML.
Conclusioni
In
questo articolo abbiamo visto le potenzialità delle applicazioni
XML sviluppate con Java. In particolare abbiamo esaminato JAXP, che rappresenta
il contributo Sun sul fronte XML, ma abbiamo anche visto che vi sono diversi
e interessanti tool di terze parti per sviluppare applicazioni XML con
Java. Ci sarebbero molti altri aspetti interessanti da esaminare, come
ad esempio l'utilizzo di XML con specifiche tecnologie Java come EJB e
JMS. Per ulteriori approfondimenti si possono trovare alcuni link nella
sezione Riferimenti.
Riferimenti
-
http://java.sun.com/xml:
sito della Sun dedicato a Java e XML.
-
http://www.w3.org:
sito del World Wide Web Consortium.
-
http://www.ibm.com/xml:
fornisce vari articoli, tool e informazioni su XML con particolare riferimento
a Java.
-
http://xml.apache.org:
sito dell'XML Apache Group.
-
http://www.xbeans.org:
sito del progetto Open Source XBeans basato sull'utilizzo di Java Bean
per l'elaborazione di documenti XML in applicazioni distribuite.
|