Linguaggi XML
Famiglia di linguaggi XML: introduzione
All'interno della categoria che prende il nome di famiglia di linguaggi XML rientrano una serie di tecnologie sviluppate negli ultimi anni che hanno a comune il fatto di essere basate su XML. L'Extensible Markup Language (XML) è un metalinguaggio, ovvero un insieme di regole base utilizzate per creare altri linguaggi. Dalla sua nascita avvenuta nel 1998, ha assunto un ruolo centrale per quanto riguarda lo sviluppo di nuove tecnologie in ambito Web e non solo. XML permette di creare nuovi linguaggi per rappresentare l'informazione strutturata in formato testuale. Il suo successo è dovuto a molti motivi e tra i principali possiamo sicuramente includere la sua semplicità, la sua espandibilità e la sua portabilità. La specifica di XML descrive un insieme di regole per definire linguaggi basati su tag (marcatori) all'interno dei quali inserire in maniera strutturata il contenuto informativo da rappresentare. 1). I tag devono essere inseriti correttamente l'uno dentro l'altro, 2). Ad ogni tag di apertura deve corrispondere un tag di chiusura 3). Gli attributi dei tag devono essere racchiusi tra apici.
Utilizzando queste semplici ed essenziali regole l'utente ha la possibilità di creare un nuovo linguaggio definendo i tag e gli attributi più appropriati a memorizzare l'informazione che si vuole trattare. Inoltre XML favorisce l'interoperabilità in quanto è un formato testuale, quindi facilmente trasferibile ed elaborabile su differenti piattaforme hardware e software. Una caratteristica fondamentale di XML è quella di occuparsi del contenuto dell'informazione e non la sua rappresentazione. La modalità di rappresentazione dell'informazione può essere scelta in un secondo momento e, partendo dallo stesso file XML, possiamo rappresentare l'informazione contenuta al suo interno in differenti modi, come ad esempio in HTML, XHTML, SVG, etc. Come esempio vediamo adesso di memorizzare in formato xml le informazioni relative ad una rubrica. Tipicamente in una rubrica, sono conservati alcuni dati (quali ad esempio nome, cognome, indirizzo, numero di telefono) riguardanti una determinata persona e tutto questo in XML può essere espresso con:
<?xml version="1.0"?>
<rubrica>
  <persona>
    <nome>Mario</nome>
    <cognome>Rossi</cognome>
    <indirizzo>
      <via>via bianchi 1</via>
      <cap>00000</cap>
      <citta>Roma</citta>
      <email>m.rossi@tin.it</email>
    </indirizzo>
    <telefono>
      <telefono_fisso>123456</telefono_fisso>
      <cellulare>987656412</cellulare>
    </telefono>
  </persona>
</rubrica>

In questo esempio abbiamo descritto in formato XML le informazioni relative ad una rubrica, andando a creare gli opportuni tag ed annidandoli in modo tale da rappresentare la struttura dati che avevamo in mente.

Proprio a causa delle caratteristiche descritte, XML ha incontrato molto successo come formato per lo scambio di dati tra applicazioni differenti.

Affinché due applicazioni possano scambiarsi dei dati in formato XML è necessario però che queste conoscano come viene strutturata l'informazione all'interno del file, ovvero quali sono e come sono chiamati i tag e gli attributi che costituiscono il file XML.

Per questo scopo sono state sviluppate alcune tecnologie quali XML Namespace, Dtd e XML Schema.

Sintassi dei NameSpace(Spazio dei Nomi)

XML Namespace nasce con lo scopo di evitare possibili ambiguità tra i nomi degli elementi che fanno parte di un linguaggio basato su XML, visto che utilizzando i Namespace siamo in grado di identificare univocamente i nomi dei tag e degli attributi.

Un XML Namespace è un insieme di nomi, utilizzato per definire gli elementi e gli attributi di un linguaggio XML, a cui viene associato un URI (Universal Resource Identifier) di riferimento tramite il quale identificare in maniera assoluta il namespace. Un URI (Universal Resource Identifier) è una stringa di caratteri che definisce il nome di una risorsa sul web ed è per definizione unica. A questo insieme di nomi viene associato un prefisso che utilizzato in abbinata con il nome dell'elemento, permette di riferire univocamente tutti gli elementi.

Come esempio vediamo di definire un namespace per l'insieme di elementi utilizzati per descrivere la rubrica.

<?xml version="1.0"?>
<mia_rubrica:rubrica xmlns:mia_rubrica="http://indirizzo_del_sito/mia_rubrica_ns">
  <mia_rubrica:persona>
    <mia_rubrica:nome>Mario</mia_rubrica:nome>
    <mia_rubrica:cognome>Rossi</mia_rubrica:cognome>
    <mia_rubrica:indirizzo>
      <mia_rubrica:via>via bianchi 1</mia_rubrica:via>
      <mia_rubrica:cap>00000</mia_rubrica:cap>
      <mia_rubrica:citta>Roma</mia_rubrica:citta>
      <mia_rubrica:emali>m.rossi@tin.it</mia_rubrica:email>
    </mia_rubrica:indirizzo>
    <mia_rubrica:telefono>
      <mia_rubrica:telefono_fisso>123456</mia_rubrica:telefono_fisso>
      <mia_rubrica:cellulare>987656412</mia_rubrica:cellulare>
    </mia_rubrica:telefono>
  </mia_rubrica:persona>
</mia_rubrica:rubrica>

Attraverso l'attributo xmlns (inserito nel primo tag del nostro file) definiamo l'URI di riferimento associato al nostro namespace e gli assegniamo un prefisso (mia_rubrica) che sarà utilizzato in abbinata con il nome dell'elemento per identificare in maniera univoca gli elementi del nostro file.

In un documento XML si fa riferimento ad un namespace utilizzando un attributo speciale (xmlns) associato al root element, come nel seguente esempio:

<articolo xmlns="http://www.dominio.it/xml/articolo">

Questo indica che l'elemento articolo ed i suoi sottoelementi utilizzano i nomi definiti nel namespace identificato dall'identificatore http://www.dominio.it/xml/articolo.

L'identificatore di un namespace può essere rappresentato da una qualsiasi stringa, purché sia univoca. Proprio per garantirne l'univocità, è prassi ormai consolidata utilizzare un URI (Uniform Resource Identifier) come identificatore.

È bene evidenziare che non è necessario che l'indirizzo specificato come identificatore di namespace corrisponda ad un file pubblicato sul Web. Esso è utilizzato semplicemente come identificatore ed il parser non accederà al Web per verificare l'esistenza dell'URL.

Per quanto riguarda la descrizione della struttura di un file XML, esistono due tecnologie: Dtd e XML Schema.

Dtd: Document Type Definition

Document Type Definition (Dtd) è un linguaggio utilizzato per definire la struttura di un file XML ed è storicamente il primo metodo utilizzato per tale scopo. È caratterizzato da una sintassi complessa, difficilmente estendibile e totalmente estranea al mondo XML, ma molto facile da usare.

Per vedere un esempio di Dtd proviamo a definire la struttura del nostro file XML che descrive la rubrica.

<!DOCTYPE rubrica [
<!ELEMENT rubrica (persona)>
<!ELEMENT persona (nome, cognome, indirizzo, telefono)>
<!ELEMENT nome (#PCDATA)>
<!ELEMENT cognome (#PCDATA)>
<!ELEMENT nome (#PCDATA)>
<!ELEMENT indirizzo (via, cap, citta, email)>
<!ELEMENT via (#PCDATA)>
<!ELEMENT cap (#PCDATA)>
<!ELEMENT citta (#PCDATA)>
<!ELEMENT email (#PCDATA)>
<!ELEMENT telefono (telefono_fisso, cellulare)>
<!ELEMENT telefono_fisso (#PCDATA)>
<!ELEMENT cellulare (#PCDATA)>
]>

Da un punto di vista cronologico, il primo approccio per la definizione di grammatiche per documenti XML è rappresentato dai Document Type Definition (DTD).

Un Dtd è un documento che descrive i tag utilizzabili in un documento XML, la loro reciproca relazione nei confronti della struttura del documento e altre informazioni sugli attributi di ciascun tag.

La sintassi di un Dtd si basa principalmente sulla presenza di due dichiarazioni: <!ELEMENT> e <!ATTLIST>. La prima definisce gli elementi utilizzabili nel documento e la struttura del documento stesso, la seconda definisce la lista di attributi per ciascun elemento. Ad esempio, la dichiarazione

<!ELEMENT articolo(paragrafo+)>

indica che l'elemento <articolo> ha come sottoelemento uno o più elementi <paragrafo>. Il carattere '+', dopo il nome del sottoelemento, indica il relativo numero di occorrenze.

Un insieme di caratteri speciali ha appunto lo scopo di indicare il numero di occorrenze di un elemento. In particolare:

+indica che l'elemento è presente una o più volte
*indica che l'elemento è presente zero o più volte
?indica che l'elemento è presente zero o una sola volta

 

Per esempio, la definizione

<!ELEMENT paragrafo(immagine*, testo+)>

indica che l'elemento <paragrafo> contiene la sequenza di elementi <immagine> e <testo>. L'elemento <immagine> può essere presente zero o più volte, mentre <testo> deve essere presente almeno una volta.

Per la definizione dei tag che non contengono sottoelementi dobbiamo distinguere il caso dei tag vuoti dai tag che racchiudono testo. Nel caso di tag vuoto, come accade per <immagine>, la definizione è

<!ELEMENT immagine EMPTY>

Nel caso di elementi che racchiudono testo abbiamo una definizione analoga alla seguente:

<!ELEMENT testo (#PCDATA)>

Esiste la possibilità di definire elementi il cui contenuto non è definito a priori, possono cioè essere vuoti o contenere altri elementi senza vincoli particolari. Per definire questo tipo di elementi si utilizza la seguente dichiarazione:

<!ELEMENT elemento ANY>

Per la definizione degli attributi di ciascun tag facciamo uso della dichiarazione <!ATTLIST>. Ad esempio, la dichiarazione:

<!ATTLIST articolo titolo CDATA #REQUIRED>

indica che l'elemento <articolo> prevede un attributo titolo che può avere come valore una qualsiasi combinazione di caratteri (CDATA). L'indicazione #REQUIRED indica che la presenza dell'attributo è obbligatoria. Valori alternativi a #REQUIRED sono:

  • #IMPLIED     

    Indica che l'attributo è opzionale
  • #FIXED valore

    Indica che il valore dell'attributo è fisso ed equivale al valore specificato

Se un attributo prevede valori alternativi predefiniti è necessario specificarli al posto di CDATA, come accade per l'attributo tipo del tag <paragrafo>

<!ATTLIST paragrafo
      titolo   CDATA #REQUIRED
      tipo     (abstract|bibliografia|note) #IMPLIED
>

In questo caso vengono definiti due attributi per l'elemento <paragrafo> facendo seguire alla definizione del primo attributo (titolo) quella del secondo(tipo). L'attributo tipo, opzionale, può assumere uno tra i valori abstract, bibliografia o note.

Il seguente codice riporta il Dtd completo per un documento che descrive un articolo:

<!ELEMENT articolo(paragrafo+)>
<!ELEMENT paragrafo (immagine*, testo+, codice*)>

<!ELEMENT immagine EMPTY>
<!ELEMENT testo (#PCDATA)>
<!ELEMENT codice (#PCDATA)>

<!ATTLIST articolo titolo CDATA #REQUIRED>
<!ATTLIST paragrafo
      titolo   CDATA #IMPLIED
      tipo     (abstract|bibliografia|note) #IMPLIED
>
<!ATTLIST immagine file CDATA #REQUIRED> 

XML Schema: elementi e struttura

Utilizzando i Dtd, quindi, abbiamo un maggior controllo sulla struttura e sull'uso dei tag in un documento XML, evitando che la libertà nella definizione dei tag possa far perdere il controllo sui contenuti.

Tuttavia l'uso dei Dtd per definire la grammatica di un linguaggio di markup non sempre è del tutto soddisfacente. A parte il fatto che la sintassi utilizzata per definire un Dtd non segue le regole stesse di XML, i Dtd non consentono di specificare un tipo di dato per il valore degli attributi, né di specificare il numero minimo o massimo di occorrenze di un tag in un documento o altre caratteristiche che in determinati contesti consentirebbero di ottenere un controllo ancora più accurato sulla validità di un documento XML.

Queste limitazioni hanno spinto alla definizione di approcci alternativi per definire grammatiche per documenti XML. tra questi approcci il più noto è XML Schema.

Per ovviare alle limitazioni della Dtd è nato XML Schema, ovvero un linguaggio, basato su XML, per definire la struttura di un documento XML.

XML Schema è uno strumento molto più potente di Dtd per descrivere la struttura di un file XML in quanto è più espandibile, permette di ottenere una migliore caratterizzazione dei tipi di dati e ha una sintassi basata su XML, quindi possiamo utilizzare gli strumenti XML per lavorare con gli Schema.

La struttura del nostro esempio Rubrica, espressa con un XML Schema, diventa:

<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="rubrica" type="tipo_rubrica"/>
  <xsd:complexType name="tipo_rubrica">
    <xsd:sequence>
      <xsd:element name="persona" type="tipo_persona"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="tipo_persona">
    <xsd:sequence>
      <xsd:element name="nome" type="xsd:string"/>
      <xsd:element name="cognome" type="xsd:string"/>
      <xsd:element name="indirizzo" type="tipo_indirizzo"/>
      <xsd:element name="telefono" type="tipo_telefono"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="tipo_indirizzo">
    <xsd:sequence>
      <xsd:element name="via" type="xsd:string"/>
      <xsd:element name="cap" type="xsd:decimal"/>
      <xsd:element name="citta" type="xsd:string"/>
      <xsd:element name="email" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="tipo_telefono">
    <xsd:sequence>
      <xsd:element name="telefono_fisso" type="xsd:decimal"/>
      <xsd:element name="cellulare" type="xsd:decimal"/>
    </xsd:sequence>
  </xsd:complexType>
</xsd:schema>

Analogamente ad un Dtd, un XML Schema è una descrizione formale di una grammatica per un linguaggio di markup basato su XML. L'approccio basato sui Dtd ci consente di specificare la struttura del nostro documento XML e di ciascun tag utilizzabile al suo interno con una precisione a prima vista accettabile.

Tuttavia, se abbiamo bisogno di un maggiore controllo sugli elementi che possono trovarsi all'interno di uno specifico tipo di documenti XML, i Dtd non risultano più sufficienti.

Ad esempio, i Dtd non mettono a disposizione un meccanismo immediato per indicare che un elemento può contenere al massimo un numero predefinito di sottoelementi, né è possibile specificare che un attributo può assumere valori di un certo tipo di dato, ad esempio valori numerici.

A differenza di un Dtd, che utilizza una propria sintassi specifica, un XML Schema utilizza la stessa sintassi XML per definire la grammatica di un linguaggio di markup. La cosa può sembrare paradossale, ma è invece indice dell'estrema flessibilità di XML.

Quindi uno XML Schema è un documento XML che descrive la grammatica di un linguaggio XML utilizzando un linguaggio di markup specifico. In quanto documento XML, uno XML Schema ha un root element che contiene tutte le regole di definizione della grammatica.

La struttura generale di uno schema XML è la seguente:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
  ... Definizione della grammatica ...
</xs:schema> 

L'elemento root del documento è rappresentato dal tag <xs:schema>. Esso indica al parser che in questo documento saranno utilizzati dei tag definiti dal namespace standard del W3C.

Vedremo successivamente più in dettaglio cosa sono i namespace e come possiamo utilizzarli e definirli. Per il momento ci basti sapere che essi rappresentano un meccanismo per identificare tag appartenenti ad una specifica grammatica. Nel nostro caso questi tag speciali sono caratterizzati dal prefisso xs:.

XML Schema prevede il tag <xs:element> per la definizione degli elementi utilizzabili in un documento XML, specificando nell'attributo name il nome del relativo tag. All'interno di ciascun tag <xs:element> possiamo indicare il tipo di dato dell'elemento e possiamo definire gli eventuali attributi.

Ad esempio, la seguente definizione specifica l'elemento testo che può contenere soltanto stringhe:

<xs:element name="testo" type="xs:string" />

Questa dichiarazione corrisponde alla seguente dichiarazione Dtd:

<!ELEMENT testo (#PCDATA)>

Ma per comprendere meglio ed apprezzare la potenza degli XML Schema occorre analizzare il concetto di tipo di dato. Esistono due categorie di tipi di dato: semplici e complessi.

XML Schema: Tipi di Dato


XML Schema introduce il concetto di tipo di dato semplice per definire gli elementi che non possono contenere altri elementi e non prevedono attributi. Si possono usare tipi di dato semplici predefiniti oppure è possibile personalizzarli.

Sono previsti numerosi tipi di dato predefiniti, alcuni dei quali sono riportati nella seguente tabella:

Tipo di dato Descrizione
xs:string Stringa di caratteri
xs:integer Numero intero
xs:decimal Numero decimale
xs:boolean Valore booleano
xs:date Data
xs:time Ora
xs:uriReference URL

Ad esempio, la seguente dichiarazione:

<xs:element name="quantita" type="xs:integer" />

permette l'utilizzo dell'elemento quantita in un documento XML consentendo soltanto un contenuto di tipo intero. In altre parole, sarà considerato valido l'elemento <quantita>123</quantita> mentre non lo sarà l'elemento <quantita>uno</quantita>.

XML Schema prevede anche la possibilità di definire tipi di dato semplici personalizzati come derivazione di quelli predefiniti. Se, ad esempio, abbiamo bisogno di limitare il valore che può essere assegnato all'elemento <quantita> possiamo definirlo nel seguente modo:

<xs:element name="quantita" >
   <xs:simpleType>
      <xs:restriction base="xs:integer">
         <xs:minInclusive value="1" />
         <xs:maxInclusive value="100" />
      </xs:restriction>
   </xs:simpleType>
</xs:element>

In altre parole, la dichiarazione indica che l'elemento <quantita> è di tipo semplice e prevede una restrizione sul tipo di dato intero predefinito accettando valori compresi tra 1 e 100.

I tipi di dato complessi si riferiscono ad elementi che possono contenere altri elementi e possono avere attributi. Definire un elemento di tipo complesso corrisponde a definire la relativa struttura.

Lo schema generale per la definizione di un elemento di tipo complesso è il seguente:

<xs:element name="NOME_ELEMENTO">
   <xs:complexType>
      ... Definizione del tipo complesso ...
      ... Definizione degli attributi ...
   </xs:complexType>
</xs:element>

Se l'elemento può contenere altri elementi possiamo definire la sequenza di elementi che possono stare al suo interno utilizzando uno dei costruttori di tipi complessi previsti:

  • <xs:sequence> Consente di definire una sequenza ordinata di sottoelementi
  • <xs:choice> Consente di definire un elenco di sottoelementi alternativi
  • <xs:all> Consente di definire una sequenza non ordinata di sottoelementi

Per ciascuno di questi costruttori e per ciascun elemento è possibile definire il numero di occorrenze previste utilizzando gli attributi minOccurs e maxOccurs. Ad esempio, se l'elemento testo può essere presente una o infinite volte all'interno di un paragrafo possiamo esprimere questa condizione nel seguente modo:

<xs:element name="paragrafo">
   <xs:complexType>
      <xs:element name="testo" minOccurs="1"
      maxOccurs="unbounded"/>
   </xs:complexType>
</xs:element>

In questo caso il valore unbounded indica che non è stabilito un massimo numero di elementi testo che possono stare all'interno di un paragrafo.

La definizione della struttura di un elemento è ricorsiva, cioè contiene la definizione di ciascun elemento che può stare all'interno della struttura stessa.

Per gli elementi vuoti è prevista una definizione basata sul seguente schema:

<xs:element name="NOME_ELEMENTO">
   <xs:complexType>
      <xs:complexContent>
         <xs:extension base="xs:anyType" />
            ... Definizione degli attributi ...
      </xs:complexContent>
   </xs:complexType>
</xs:element>

In altri termini, un elemento vuoto è considerato un elemento di tipo complesso il cui contenuto non si basa su nessun tipo predefinito.

La definizione degli attributi è basata sull'uso del tag <xs:attribute>, come nel seguente esempio:

<xs:attribute name="titolo" type="xs:string" use="required" />

L'attributo use consente di specificare alcune caratteristiche come la presenza obbligatoria (required) o un valore predefinito (default) in combinazione con l'attributo value. Ad esempio, la seguente definizione indica un attributo il cui valore di predefinito è test:

<xs:attribute name="titolo" type="xs:string" use="default" value="test" />

Bisogna tener presente che se non si specifica esplicitamente l'obbligatorietà dell'attributo, esso è considerato opzionale. Il seguente codice presenta uno XML Schema relativo al linguaggio di descrizione di articoli tecnici mostrato nei vari esempi.

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:element name="articolo">
  <xs:complexType>
   <xs:sequence>
    <xs:element name="paragrafo" maxOccurs="unbounded">
     <xs:complexType>
      <xs:all maxOccurs="unbounded">
       <xs:element name="immagine" minOccurs="0">
        <xs:complexType>
         <xs:attribute name="file"
          use="required">
          <xs:simpleType>
           <xs:restriction base="xs:string"/>
          </xs:simpleType>
         </xs:attribute>
        </xs:complexType>
       </xs:element>
       <xs:element name="testo"/>
       <xs:element name="codice" minOccurs="0"/>
      </xs:all>
      <xs:attribute name="titolo" type="xs:string"
      use="optional"/>
      <xs:attribute name="tipo" use="optional">
       <xs:simpleType>
        <xs:restriction base="xs:string">
         <xs:enumeration value="abstract"/>
         <xs:enumeration
         value="bibliografia"/>
         <xs:enumeration value="note"/>
        </xs:restriction>
       </xs:simpleType>
      </xs:attribute>
     </xs:complexType>
    </xs:element>
   </xs:sequence>
   <xs:attribute name="titolo" type="xs:string"
   use="required"/>
  </xs:complexType>
 </xs:element>
</xs:schema>

Questo XML Schema è equivalente al Dtd prima vista.

XML Schema: Dichiarazione di tipi

XML Schema prevede la possibilità di rendere modulare la definizione della struttura di un documento XML tramite la dichiarazione di tipi e di elementi.

Nel corso della creazione di uno schema XML possiamo analizzare ciascun sottoelemento significativamente complesso e fornire una definizione separata come elemento o come tipo di dato.

Questo contribuisce a fornire una struttura modulare allo schema, più ordinata, più comprensibile e semplice da modificare. Sfruttando la struttura modulare delle dichiarazioni, il contenuto di uno XML Schema diventa una sequenza di dichiarazioni di tipi ed elementi.

Possiamo definire un tipo complesso in base al seguente schema:

<xs:complexType name="nome_tipo">
...
</xs:complexType>

Il riferimento ad una dichiarazione di tipo viene fatta come se fosse un tipo predefinito, come mostrato nel seguente esempio:

<xs:element name="nome_elemento" type="nome_tipo" />

La possibilità di dichiarare elementi e tipi di dato implica l'esistenza di un ambito di visibilità o contesto dei componenti dichiarati. I componenti di uno schema dichiarati al livello massimo, cioè come sottoelementi diretti dell'elemento root, sono considerati dichiarati a livello globale e possono essere utilizzati nel resto dello schema.

Nella dichiarazione di un tipo complesso è possibile fare riferimento ad elementi già esistenti dichiarati a livello globale oppure si possono definire nuovi elementi. La definizione di nuovi elementi all'interno di una definizione di tipo o di elemento costituisce una dichiarazione a livello locale. Ciò vuol dire che l'utilizzo di questi elementi è limitato alla definizione del tipo complesso in cui sono dichiarati e non possono essere utilizzati in altri punti dello schema.

I nomi degli elementi devono essere univoci nel contesto in cui compaiono. Questo significa, però, che in contesti diversi possiamo avere elementi con lo stesso nome ma con struttura diversa senza rischio di conflitti.

Per fare un'analogia con i classici linguaggi di programmazione, le dichiarazioni globali e locali di componenti di uno schema corrispondono alle dichiarazioni di variabili globali e locali in un'applicazione.

Il seguente codice riporta lo XML Schema per un linguaggio di descrizione di articoli visto nel paragrafo precedente, riorganizzato alla luce della possibilità di definire tipi di dato.

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

 <xs:element name="articolo">
  <xs:complexType>
   <xs:sequence>
    <xs:element name="paragrafo" type="paragrafoType"
    maxOccurs="unbounded"/>
   </xs:sequence>
  <xs:attribute name="titolo" type="xs:string"
  use="required"/>
  </xs:complexType>
 </xs:element>

 <xs:complexType name="paragrafoType">
  <xs:all maxOccurs="unbounded">
   <xs:element name="immagine" type="immagineType"
   minOccurs="0"/>
   <xs:element name="testo"/>
   <xs:element name="codice" minOccurs="0"/>
  </xs:all>
  <xs:attribute name="titolo" type="xs:string"
  use="optional"/>
  <xs:attribute name="tipo" use="optional">
   <xs:simpleType>
    <xs:restriction base="xs:string">
     <xs:enumeration value="abstract"/>
     <xs:enumeration value="bibliografia"/>
     <xs:enumeration value="note"/>
    </xs:restriction>
   </xs:simpleType>
  </xs:attribute>
 </xs:complexType>

 <xs:complexType name="immagineType">
  <xs:attribute name="file" use="required">
   <xs:simpleType>
    <xs:restriction base="xs:string"/>
   </xs:simpleType>
  </xs:attribute>
 </xs:complexType>

</xs:schema>

Come si può vedere, la leggibilità dello schema è molto maggiore rispetto alla prima versione. Inoltre, i tipi definiti a livello globale possono essere riutilizzati nel caso servisse modificare lo schema e quindi la struttura dei documenti XML risultanti.

XML Schema: Integrazione con i namespace

A partire da una grammatica definita tramite uno XML Schema, è possibile sfruttare un parser XML validante per verificare la validità di un documento XML. Il parser avrà bisogno, quindi, sia del documento XML da validare, sia dello schema XML rispetto a cui effettuare la validazione.

Ci sono diversi modi per fornire al parser informazioni sullo schema da utilizzare per la validazione.

Nell'ambito delle tecnologie XML, un XML Schema definisce implicitamente un namespace degli elementi e degli attributi che possono essere usati in un documento XML.

Se in un documento XML si utilizzano elementi definiti in schemi diversi abbiamo bisogno di un meccanismo che permetta di identificare ciascun namespace e il relativo XML Schema che lo definisce.

In un documento XML si fa riferimento ad un namespace utilizzando un attributo speciale (xmlns) associato al root element, come nel seguente esempio:

<articolo xmlns="http://www.dominio.it/xml/articolo">

Questo indica che l'elemento articolo ed i suoi sottoelementi utilizzano i nomi definiti nel namespace identificato dall'identificatore http://www.dominio.it/xml/articolo.

L'identificatore di un namespace può essere rappresentato da una qualsiasi stringa, purché sia univoca. Proprio per garantirne l'univocità, è prassi ormai consolidata utilizzare un URI (Uniform Resource Identifier) come identificatore.

È bene evidenziare che non è necessario che l'indirizzo specificato come identificatore di namespace corrisponda ad un file pubblicato sul Web. Esso è utilizzato semplicemente come identificatore ed il parser non accederà al Web per verificare l'esistenza dell'URL.

Per mettere in relazione un namespace con il relativo XML Schema occorre dichiararlo nel root element come nel seguente esempio:

<articolo
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.dominio.it/xml/articolo"
  xmlns=
"http://www.dominio.it/xml/bibliografia"
  xsi:schemaLocation=
"http://www.dominio.it/xml/articolo
   articolo.xsd"
  xsi:schemaLocation=
"http://www.dominio.it/xml/bibliografia
   bibliografia.xsd"
>

L'attributo xmlns:xsi specifica la modalità con cui viene indicato il riferimento allo schema, mentre l'attributo xsi:schemaLocation indica il namespace ed il file in cui è definito il relativo XML Schema separati da uno spazio.

Eì possibile combinare più namespace facendo in modo che ciascun elemento utilizzato faccia riferimento al proprio namespace.

Occorre tener presente che quando si fa riferimento ad un namespace, questo riferimento vale per l'elemento corrente e per tutti gli elementi contenuti, a meno che non venga specificato un diverso namespace.

Il seguente esempio utilizza elementi tratti da due diversi namespace: uno relativo alla grammatica della struttura di un articolo e l'altro relativo alla grammatica di bibliografie:

<articolo xmlns="http://www.dominio.it/xml/articolo" titolo="Guida ad XML">
 <paragrafo titolo="Introduzione">
  <testo>
   bla bla bla
  </testo>
 </paragrafo>
 <paragrafo titolo="Bibliografia">
  <bibliografia
   xmlns=
quot;http://www.dominio.it/xml/bibliografia">
   <autore>
    Tizio
   </autore>
   <titolo>
    Opera citata
   </titolo>
   <anno>
    1999
   </anno>
  </bibliografia>
 </paragrafo>
</articolo>

Riportare il riferimento ad un namespace per ogni elemento è di solito scomodo e rende di difficile lettura il documento XML. È possibile creare delle abbreviazioni per fare riferimento ai namespace.

Queste abbreviazioni sono costituite da caratteri alfanumerici seguiti da due punti (:) dichiarati nel root element ed utilizzati come prefissi dei nomi degli elementi. Il seguente esempio riporta il codice XML precedente facendo uso di questi prefissi:

<art:articolo titolo="Guida ad XML"
 xmlns:art="http://www.dominio.it/xml/articolo"  
 xmlns:bibl=
"http://www.dominio.it/xml/bibliografia" >
  <art:paragrafo titolo="Introduzione">
   <art:testo>
    bla bla bla
   </art:testo>
  </art:paragrafo>
  <art:paragrafo titolo="Bibliografia">
   <bibl:bibliografia>
    <bibl:autore>
     Tizio
    </bibl:autore>
    <bibl:titolo>
     Opera citata
    </bibl:titolo>
    <bibl:anno>
     1999
    </bibl:anno>
   </bibl:bibliografia>
 </art:paragrafo>
</art:articolo>

Le dichiarazioni xmlns:art e xmlns:bibl assegnano i prefissi art: e bibl: ai relativi namespace e questi prefissi vengono utilizzati per ciascun elemento del documento XML.

Presentazione di XML con CSS

A differenza di HTML, che è un linguaggio specifico di strutturazione e presentazione di documenti, XML è più generale e non ha una semantica di presentazione. Non è previsto alcun meccanismo predefinito per visualizzare i vari elementi di un documento.

Ad esempio, un documento XML visualizzato in un browser appare generalmente così com'è, al massimo con una indentazione e una colorazione dei tag impostata dal browser.

Un metodo per gestire la presentazione del contenuto di un documento XML consiste nell'utilizzare i Cascading Style Sheets (CSS).

È possibile utilizzare i CSS in modo analogo a come si utilizzano con HTML. Per ciascun elemento del documento XML che vogliamo formattare occorre definire una regola secondo lo schema:

selettore { proprietà: valore; proprietà: valore; ... }

Il selettore specifica a quale elemento la regola deve essere applicata, mentre la parte racchiusa tra parentesi graffe elenca le caratteristiche da impostare e il relativo valore.

È opportuno evidenziare una importante differenza tra l'utilizzo dei CSS per formattare documenti HTML e il loro uso per i documenti XML. In HTML la maggior parte dei tag ha una formattazione predefinita e pertanto un foglio di stile CSS consente di ridefinire tali impostazioni.

In XML i tag non hanno alcun significato di formattazione, pertanto è necessario specificare tutto. Ad esempio, senza l'opportuna indicazione il testo contenuto nei diversi elementi di un documento XML verrebbe visualizzato come un'unica stringa.

Per strutturare visivamente il documento dobbiamo indicare la modalità di visualizzazione di ciascun elemento tramite la proprietà display di CSS. Ad esempio, per formattare l'elemento paragrafo di un articolo possiamo definire una regola come la seguente:

paragrafo {display: block; font-size: 12pt; text-align: left}

Generalmente un foglio di stile CSS da applicare ad un documento XML viene salvato in un file di testo con estensione .css (in realtà l'estensione usata è irrilevante). Nel documento XML possiamo quindi inserire un riferimento ad esso mediante unìapposita direttiva di elaborazione, come nel seguente esempio:

<?xml-stylesheet type="text/css" href="stile.css" ?>

Questa dichiarazione fa in modo che un browser abilitato applichi le impostazioni del foglio di stile CSS specificato al documento XML.

I fogli di stile CSS sono pensati principalmente per il Web e mancano pertanto di alcune caratteristiche che possono risultare utili in ambiti diversi. Ad esempio, per la presentazione su supporti cartacei occorrerebbero maggiori funzionalità per l'impaginazione. tra le principali limitazioni, non è prevista la possibilità di estrarre il valore degli attributi degli elementi in modo da poterli visualizzare.

Considerando il seguente esempio

<articolo titolo="Guida ad XML">

non abbiamo la possibilità di visualizzare il titolo dell'articolo che è stato espresso come attributo dell'elemento <articolo>. Questo costringerebbe a dover strutturare un documento XML in funzione della sua formattazione con CSS, in evidente contraddizione con lo stesso concetto di foglio di stile che tende a separare la definizione dei dati dalla sua presentazione.

Inoltre, non sempre un documento XML descrive qualcosa di visualizzabile con un browser. Ad esempio, è possibile definire un linguaggio XML per la descrizione di immagini o di ambienti virtuali. In questo caso i CSS non sono di alcun aiuto nella presentazione del documento.

Per risolvere questi problemi il W3C ha definito un'insieme di specifiche volte a gestire in maniera altamente flessibile la presentazione e la trasformazione di documenti XML: l'eXtensible Stylesheet Language (XSL).

XSL: eXtensible Stylesheet Language

L'eXtensible Stylesheet Language (XSL) è un insieme di tre linguaggi che forniscono gli strumenti per l'elaborazione e la presentazione di documenti XML in maniera molto flessibile.

La definizione di questa tecnologia si basa sull'osservazione del processo di presentazione di dati di qualsiasi natura. Infatti, in un tale processo possiamo individuare i seguenti meccanismi di base:

  • un meccanismo per l'individuazione dei dati da presentare
  • un meccanismo per il controllo dell'elaborazione dei dati e di come la presentazione deve essere effettuata
  • un meccanismo per la definizione della formattazione da applicare ai dati per la presentazione vera e propria

A ciascuno di questi tre meccanismi, XSL associa uno specifico linguaggio:

  • XPath consente di individuare gli elementi e gli attributi di un documento XML sui quali verranno applicate le operazioni necessarie per la presentazione dei dati
  • XSLT (XSL transformation) consente di controllare le operazioni che rendono i dati presentabili
  • XSL-FO (XSL Formatting Objects) definisce un insieme di tag di formattazione

Questa suddivisione dei compiti nel processo di presentazione è il punto di forza di XSL e ne garantisce la flessibilità. Infatti, questi tre linguaggi non sono strettamente dipendenti l'uno dall'altro.

Se, ad esempio, in una particolare applicazione ci rendiamo conto che XPath non soddisfa le nostre esigenze di ricerca di elementi in un documento XML, potremmo utilizzare linguaggio analogo (XQL, per citarne uno) ma senza modificare la presentazione dei caratteri.

Oppure potremmo decidere di non utilizzare affatto XSL-FO per formattare i dati di un documento XML e produrre direttamente codice HTML, o meglio XHTML, cioè la versione di HTML basata su XML.

La presentazione dei dati racchiusi in un documento XML è basata su due elementi:

  • un documento che descrive come i dati devono essere elaborati per la presentazione, chiamato foglio di stile XSLT
  • un componente software, chiamato processore XSLT, in grado di prendere in input un documento XML e un foglio di stile XSLT e di produrre in output i dati secondo il formato di presentazione prescelto (XSL-FO, XHTML, testo, ecc.)

La definizione di un foglio di stile XSLT è quindi il punto cruciale della presentazione dei dati XML. Le regole di trasformazione presenti in un foglio XSLT consentono di selezionare gli elementi di un documento XML e di gestirne la modalità di presentazione. Come abbiamo giù detto, nella definizione standard di XSLT la selezione degli elementi da presentare viene fatta tramite il linguaggio XPath.

XPath

Iniziamo con questo capitolo, la panoramica sulle tecnologie della famiglia XML andando a parlare di XPath.
XPath è un linguaggio tramite il quale è possibile esprimere delle espressioni per indirizzare parti di un documento XML. È un linguaggio ideato per operare all'interno di altre tecnologie XML (di cui parleremo nei capitolo successivi), quali XSL e XPointer, ed è caratterizzato dal fatto di avere una sintassi non XML. In questo modo può essere meglio utilizzato all'interno di URI o come valore di attributi di documenti XML.
XPath opera su una rappresentazione logica del documento XML, che viene modellato con una struttura ad albero ed XPath definisce una sintassi per accedere ai nodi di tale albero.
Oltre a questo XPath mette a disposizione una serie di funzioni per la manipolazione di stringhe, numeri e booleani, da utilizzare per operare sui valori o sugli attributi dei nodi.
Le espressioni definite da XPath per accedere ai nodi dell'albero prendono il nome di Location Path (percorsi di localizzazione).
La struttura un location path è la seguente:
axis::node-test[predicate].

La componente axis esprime la relazione di parentela tra il nodo cercato ed il nodo corrente; la componente node-test specifica il tipo o il nome del nodo da cercare; mentre predicate contiene zero o più filtri (espressi tra parentesi quadre) per specificare delle condizioni più selettive da applicare alla ricerca.
Le relazioni di parentela principali che possono essere contenute in axis sono:

  • ancestor:   indica tutti i nodi antenati del nodo corrente, ovvero tutti i nodi che lo precedono nell'albero associato al documento XML;
  • attribute indica tutti gli attributi del nodo corrente;
  • child indica i nodi figli del nodo corrente;
  • descendant:   indica tutti i discendenti del nodo corrente, ovvero tutti i nodi che hanno seguono il nodo corrente nell'albero XML;
  • parent:   indica il nodo genitore del nodo corrente, ovvero quello che lo precede nell'albero;
  • self:   indica il nodo corrente.

Vediamo qualche esempio per capire meglio come utilizzare i Location Path per accedere agli elementi di un documento XML, utilizzando l'esempio della rubrica introdotto nel capitolo precedente, anche se con qualche piccola modifica.

<?xml version="1.0"?>
<rubrica>
  <persona>
    <nome>Mario</nome>
    <cognome>Rossi</cognome>
    <indirizzo>
      <via>via bianchi 1</via>
      <cap>00000</cap>
      <citta>Roma</citta>
    </indirizzo>
    <telefono>
      <telefono_fisso gestore="Abc">123456</telefono_fisso>
      <telefono_cellulare gestore=
"Def">987656412</telefono_cellulare>
    </telefono>
  </persona>
</rubrica>

child::nome
Questa espressione seleziona tutti i nodo chiamati 'nome' che sono figli del nodo corrente.
child::*
Seleziona tutti i nodi figli del nodo corrente.
attribute::gestore
Seleziona l'attributo di nome 'gestore' del nodo corrente.
descendant::cognome[cognome='Rossi']
Seleziona tutti i nodi chiamati 'cognome' tra i nodi discendenti del nodo corrente, il cui valore è Rossi.

In XPath è possibile accedere ai nodi dell'albero utilizzando delle espressioni abbreviate dei Location Path.
Le espressioni abbreviate, come suggerisce il nome stesso, sono una versione semplificata e compatta dei Location Path ed offrono un meccanismo più veloce, ma al tempo stesso meno potente per accedere ai nodi dell'albero. Queste espressioni sono costituite da una lista di nomi di elementi del documento XML, separati da uno slash(/), e tale lista descrive il percorso per accedere all'elemento desiderato.
È un meccanismo molto simile a quello usato per identificare i file e le directory nel filesystem. Ad esempio per indicare il file (chiamato mio-file) memorizzato all'interno di una directory (chiamata mia-directory) del vostro hard disk, utilizzate la seguente sintassi: c:directory1file1.
Le espressioni abbreviate di XPath utilizzano un meccanismo concettualmente simile: vediamo come, utilizzando il solito file XML d'esempio.

/rubrica/persona/nome Questa espressione abbreviata permette di recuperare i nodi chiamati 'nome' indicando il percorso assoluto per raggiungere il nodo desiderato, attraverso una lista di nodi separata da slash.

//nome
Con il doppio slash ricerchiamo i nodi chiamati 'nome', in tutto il documento, indipendentemente dalla loro posizione e dal loro livello sull'albero associato al documento XML.
/rubrica//via
Ricerchiamo tutti i nodi chiamati 'via' a qualsiasi livello dell'albero purchè contenuti all'interno del nodo chiamato 'rubrica'.
/rubrica/persona/*
Ricerca qualsiasi elemento figlio del nodo chiamato 'persona'.
//nome/@valuta
Ricerca l'attributo 'valuta' dell'elemento 'nome'. Anche all'interno delle espressioni abbreviate possiamo inserire i predicati visti nel caso dei Location Path. Ad esempio: //persona[nome='Mario']
questa espressione ricerca tutti i nodi 'persona' che hanno il tag 'nome' il cui valore è Mario.

Come detto all'inizio del capitolo, XPath mette a disposizione anche delle funzioni per gestire i nodi, le stringhe, i numeri e i booleani. Vediamo adesso di elencare brevemente e schematicamente alcune funzioni principali:

  • count(node-set):   restituisce il numero di nodi contenuti nell'insieme di nodi passato come argomento della funzione;
  • name(nodo):   restituisce il nome di un nodo;
  • position():   determina la posizione di un elemento all'interno di un insieme di nodi;
  • last():   indica la posizione dell'ultimo nodo di un'insieme di nodi;
  • id(valore):   seleziona gli elementi in funzione del loro identificatore;
  • concat(s1,...,sn):   restituisce una stringa risultato della concatenazione delle stringhe specificate tra gli argomenti di una funzione;
  • string(valore):   converte il valore dell'argomento in una stringa;
  • string-length(stringa):   ritorna la lunghezza della stringa passata come parametro;
  • substring(stringa,inizio,lunghezza):   restituisce una sotto-stringa della stringa passata come argomento;
  • ceiling(numero):   arrotonda il numero per eccesso;
  • floor(numero):   arrotonda il numero per difetto;
  • number(valore):   converte il valore dell'argomento in un numero;
  • sum(node-set):   esprime la somma di un insieme di valori numerici contenuti in un insieme di nodi.

Come esempi di espressioni XPath che fanno uso di queste funzioni consideriamo:
//persona[last()]
Questa espressione restituisce l'ultimo nodo 'persona' contenuto all'interno del file XML.
//persona[position()= 3]
Restituisce il terzo nodo 'persona' contenuto all'interno del file XML.
count(/rubrica/persona)
Indica il il numero di nodi chiamati 'persona' contenuti all'interno del documento XML.

XSLT

Una caratteristica fondamentale di XML è quella di occuparsi esclusivamente della descrizione del contenuto dell'informazione e non della sua rappresentazione.
Infatti i tag XML non esprimono in alcun modo come verrà visualizzato il loro contenuto, cosa che invece accade in altri linguaggi basati su marcatori, come HTML.
L'informazione contenuta in un file XML può essere visualizzata definendo degli stili di rappresentazione, che, applicati al file XML, saranno in grado di rappresentarne il contenuto nel modo desiderato.
In XML questo può essere fatto utilizzando XSL (eXtensible Stylesheet Language). XSL è un linguaggio basato su XML per esprimere i fogli di stile, ossia un documento contenente le regole per rappresentare l'informazione. XSL è composto da due componenti: XSLT (eXtensible Stylesheet Language transformation), che descriveremo in questo capitolo, e XSL-FO (eXtensible Stylesheet Language - Formatting Objects), che analizzeremo nel prossimo capitolo.
All'interno di XSL viene utilizzato XPath per la ricerca ed il filtraggio dei contenuti del file XML.

XSLT è un linguaggio basato su XML che permette di definire delle regole per trasformare un documento XML in un altro documento XML o in un documento HTML. Utilizzando XSL possiamo ad esempio visualizzare il contenuto di un documento XML in HTML, XHTML o SVG.
La trasformazione viene realizzata da un XSLT Processor che riceve come input il file XML da trasformare, il file XSL con la definizione dello stylesheet da applicare e produce come output il file trasformato. Un file XSL è formato da una serie di template (modelli) che contengono le regole di trasformazione dei tag del documento XML. Questi template vengono applicati ai tag corrispondenti dal XSLT Processor in maniera ricorsiva nel corso della trasformazione.
Come esempio vediamo di definire un file XSL per visualizzare un file XML di esempio in una pagina HTML.
Il file XML di input è:

<?xml version="1.0"?>
<rubrica>
  <persona>
    <nome>Mario</nome>
    <cognome>Rossi</cognome>
    <indirizzo>
      <via>via bianchi 1</via>
      <cap>00000</cap>
      <citta>Roma</citta>
    </indirizzo>
    <telefono>
      <telefono_fisso>123456</telefono_fisso>
      <telefono_cellulare>
987656412</telefono_cellulare>
    </telefono>
  </persona>
</rubrica>

Il file XSL con la definizione dello stile per la creazione del file HTML è:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/transform" version="1.0">
  <xsl:template match="/">
    <html>
      <head>
        <title>Rubrica in versione HTML</title>
      </head>
      <body>
        <h1>Rubrica</h1>
        <xsl:apply-templates/>
      </body>
    </html>  
  </xsl:template>
  <xsl:template match="persona">
    <h2> <xsl:value-of select="cognome"/>&#160;<xsl:value-of select="nome"/> </h2>
    <ul>
      <li>Via: <xsl:value-of select="./indirizzo/via"/></li>
      <li>CAP: <xsl:value-of select="./indirizzo/cap"/></li>
      <li>Citta': <xsl:value-of select="./indirizzo/citta"/></li>
      <li>Telefono (fisso): <xsl:value-of select="./telefono/telefono_fisso"/></li>
      <li>Telefono (cellulare): <xsl:value-of select="./telefono/telefono_cellulare"/></li>
    </ul>
  </xsl:template>
</xsl:stylesheet>

In un file XSL le regole di trasformazione sono contenute all'interno degli elementi template e tramite l'attributo match possiamo specificare, utilizzando la sintassi XPath, il tag a cui si riferiscono queste regole. Nel nostro esempio il primo elemento template contiene le regole di trasformazione dell'elemento root del file di input (l'elemento <rubrica>); mentre il secondo definisce le regole per la trasformazione degli elementi <persona>.
Il processore XSLT effettua il parsing del documento XML da trasformare e, per ogni nodo incontrato, ricerca il template appropriato all'interno del file XSL.
Quando il processore incontra il nodo root del documento XML applica il primo template e quindi costruisce lo scheletro del file HTML. Con l'elemento <xsl:apply-templates> si indica al processore XSLT di analizzare i nodi figli del nodo corrente alla ricerca di altri template da applicare.

Il risultato prodotto dalla trasformazione XSLT è il seguente:

<html>
  <head>
    <title>Rubrica in versione HTML</title>
  </head>
  <body>
    <h1>Rubrica</h1>
    <h2>Rossi Mario</h2>
      <ul>
        <li>Via: via bianchi 1</li>
        <li>CAP: 00000</li>
        <li>Citta': Roma</li>
        <li>Telefono (fisso): 123456</li>
        <li>Telefono (cellulare): 987656412</li>
      </ul>
  </body>
</html>  

Lo stesso file XML può essere trasformato in un'immagine SVG utilizzando il seguente file XSL:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/transform" version="1.0">
  <xsl:template match="/">
    <svg width="400" height="200">
      <title>Rubrica in versione SVG</title>
      <xsl:apply-templates/>
    </svg>  
  </xsl:template>
  <xsl:template match="persona">
    <rect x="10" y="10" width="180" height="30" fill="lightblue" stroke="blue" stroke-width="2"/>
    <text x="20" y="30" font-family="times" font-width="20" fill="black">
      <xsl:value-of select="cognome"/>&#160;<xsl:value-of select="nome"/>
    </text>
    <rect x="10" y="40" width="200" height="150" fill="white" stroke="blue" stroke-width="2"/>
    <text x="20" y="60" font-family="times" font-width="20" fill="blue">
      Via: <xsl:value-of select="./indirizzo/via"/>
    </text>
    <text x="20" y="80" font-family="times" font-width="20" fill="blue">
      CAP: <xsl:value-of select="./indirizzo/cap"/>
    </text>
    <text x="20" y="100" font-family="times" font-width="20" fill="blue">
      Citta': <xsl:value-of select="./indirizzo/citta"/>
    </text>
    <text x="20" y="120" font-family="times" font-width="20" fill="blue">
      Telefono (fisso): <xsl:value-of select="./telefono/telefono_fisso"/>
    </text>
    <text x="20" y="140" font-family="times" font-width="20" fill="blue">
      Telefono (cellulare): <xsl:value-of select="./telefono/telefono_cellulare"/>
    </text>
  </xsl:template>
</xsl:stylesheet>

Il risultato della trasformazione è il seguente:

<svg width="400" height="200">
  <title>Rubrica in versione SVG</title>
  <rect x="10" y="10" width="180" height="30" fill="lightblue" stroke="blue" stroke-width="2"/>
  <text x="20" y="30" font-family="times" font-width="20" fill="black">Rossi Mario</text>
  <rect x="10" y="40" width="200" height="150" fill="white" stroke="blue" stroke-width="2"/>
  <text x="20" y="60" font-family="times" font-width="20" fill="blue">Via: via bianchi 1</text>
  <text x="20" y="80" font-family="times" font-width="20" fill="blue">CAP: 00000</text>
  <text x="20" y="100" font-family="times" font-width="20" fill="blue">Citta': Roma</text>
  <text x="20" y="120" font-family="times" font-width="20" fill="blue">Telefono (fisso): 123456</text>
  <text x="20" y="140" font-family="times" font-width="20" fill="blue">Telefono (cellulare): 987656412</text>
</svg>

XSLT è uno strumento grazie al quale possiamo decidere di visualizzare gli stessi dati contenuti in un file XML in differenti modi a seconda delle nostre esigenze ed il tutto in maniera assolutamente automatica.

XSL-FO

In questo capitolo andiamo ad analizzare la seconda componente di XSL, XSL-FO.
XSL-Formatting Objects è un linguaggio, anch'esso basato su XML, per la specifica di una semantica di formattazione dei contenuti di un documento XML. All'interno di un documento XSL-FO possiamo definire le regole di impaginazione delle informazioni che vogliamo visualizzare, andando ad esprimere la posizione dei singoli contenuti nella pagina.
Grazie a XSL-FO possiamo produrre, ad esempio dei documenti PDF, RTF o PS, rappresentanti il contenuto di un documento XML. Il documento XSL-FO viene analizzato da un processore XSL-FO che si occupa di produrre il documento di output, in base alle regole specificate nel documento di input.
La struttura di un file XSL-FO è la seguente:

<?xml version="1.0"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>    
    <!--modello pagina-->
  </fo:layout-master-set>

  <fo:declarations>
    <!--dichiarazioni globali-->
  </fo:declarations>
  
  <fo:page-sequence>
    <!--contenuti pagine-->
  </fo:page-sequence>
</fo:root>

All'interno dell'elemento <layout-master-set> vanno inserite le regole di impaginazione per la pagina master, ovvero la pagina che costituisce il modello per tutte le altre pagine del documento. Il secondo elemento (<declarations>)contiene eventuali dichiarazioni globali al file XSL-FO; mentre l'elemento <page-seguence> contiene la definizione delle informazioni contenute nelle pagine che costituiranno il documento finale.
Per cercare di capire meglio il funzionamento di XSL-FO vediamo di analizzare il seguente documento di esempio:

<?xml version="1.0"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <fo:layout-master-set>    
    <fo:simple-page-master master-name="PaginaA4"
      page-height="29.7cm" page-width="21cm" margin-top="1.5cm"
      margin-bottom="1.5cm" margin-left="2.5cm" margin-right="2.5cm">
      <fo:region-body margin-top="1.8cm"/>
      <fo:region-before extent="1.3cm"/>
      <fo:region-after extent="1.3cm"/>
    </fo:simple-page-master>
  </fo:layout-master-set>  
  <fo:page-sequence master-reference="PaginaA4">
    <fo:title>Esempio XSL-FO</fo:title>
    <fo:static-content flow-name="xsl-region-before">
      <fo:block text-align="end" font-size="8pt" font-family="times">
        Esempio XSL-FO
      </fo:block>  
    </fo:static-content>
    <fo:static-content flow-name="xsl-region-after">
      <fo:block text-align="end" font-size="8pt" font-family="times">
        Pagina <fo:page-number/>
      </fo:block>  
    </fo:static-content>
    <fo:flow flow-name="xsl-region-body">
      <fo:block text-align="center" font-size="14pt" font-family="times" color="blue">
        Testo della prima pagina dell'esempio XSL-FO.
      </fo:block>
      <fo:block break-before="page" text-align="center" font-size="14pt" font-family="times" color="green">
        Testo della seconda pagina dell'esempio XSL-FO.
      </fo:block>
    </fo:flow>
  </fo:page-sequence>
</fo:root>

Come detto in precedenza, il modello della pagina master viene definito con l'elemento <single-page-master>.
Nel nostro caso, al suo interno, abbiamo specificato le misure di un foglio in formato A4 utilizzando gli attributi dell'elemento.
Inoltre abbiamo indicato anche la dimensione dell'intestazione (con l'elemento <region-before>), la dimensione del piè di pagina (con l'elemento <region-after>) e del contenuto della pagina (con l'elemento <region-body>).
Una volta stabilito il modello della pagina andiamo a specificare il contenuto delle pagine del nostro documento con l'elemento <page-sequence>.
Gli elementi che troviamo al suo interno sono:

  • <title>: permette di specificare il titolo del documento;
  • <static-content>: indica le informazioni che verranno ripetute in ogni pagina;
  • <flow>: elemento che contiene il contenuto delle pagine.

Nel nostro esempio abbiamo definito, in <static-content>, l'intestazione delle pagine del documento contenente il titolo e il piè di pagina con il numero di pagina, che viene calcolato in maniera automatica grazie al tag <page-number>.
Nell'elemento <flow> abbiamo definito il contenuto delle due pagine che costituiscono il nostro esempio.
Il risultato della trasformazione del documento di esempio da parte del processore XSL-FO è il documento PDF mostrato in figura.

Se volessimo creare un documento XSL-FO in grado di visualizzare il contenuto di un documento XML allora sarebbe necessario applicare una prima trasformazione XSLT al file XML, in modo da produrre il file XSL-FO con le regole di impaginazione. Una volta prodotto questo documento saremmo in grado di utilizzare il processore XSL-FO per creare, ad esempio, un documento PDF contenente i dati del documento XML di partenza.