Uno dei concetti più difficili da digerire per chi si avvicina per la prima volta a XML e agli XML Schema è quello di namespace. Nei confronti tra colleghi e nei corsi che ho avuto occasione di tenere, la presenza in un documento XML di tag con prefissi e l'indicazione del fatidico attributo xmlns ha sempre creato panico.
In questo articolo vorrei provare a dileguare il panico da namespace cercando di spiegarne il funzionamento e le finalità.
Il problema
Uno dei grandi vantaggi di XML deriva dal fatto che esso è un metalinguaggio, cioè un linguaggio per creare altri linguaggi di markup. Questa caratteristica ci offre la libertà di crearci il nostro linguaggio lasciandoci decidere come vogliamo strutturare un documento e quali tag utilizzare.
Quindi, se voglio creare un mio linguaggio di markup per definire, ad esempio, ricette da cucina, non ho da fare altro che definire la struttura che voglio dare alle ricette e i tag da utilizzare. Supponiamo di aver deciso di definire una ricetta nel nostro linguaggio, chiamiamolo XMLRicette, e che il seguente sia un esempio di ricetta:
Listato 1. Esempio di ricetta in XML
<ricetta>
<titolo>Pasta, aglio olio e peperoncino</titolo>
<autore>Anonimo</autore>
<ingredienti>
<ingrediente>200 gr. di spaghetti</ingrediente>
<ingrediente>uno spicchio di aglio</ingrediente>
<ingrediente>olio</ingrediente>
<ingrediente>un pizzico di peperoncino</ingrediente>
<ingrediente>sale</ingrediente>
<ingredienti>
<procedimento>
Far bollire dell'acqua in una pentola...
</procedimento>
</ricetta>
La struttura sembra ragionevole, la scelta dei tag pure. Siamo soddisfatti del nostro nuovo linguaggio.
Supponiamo, però, che ad un certo punto decidiamo che non sarebbe male arricchire il nostro linguaggio con la possibilità di inserire una bibliografia in fondo a ciascuna ricetta. Abbiamo sentito parlare molto di un linguaggio basato su XML che consente di definire bibliografie: XMLBiblio.
Non sarebbe male utilizzarlo per integrare il nostro XMLRicette. Avremmo il vantaggio di utilizzare un linguaggio noto e ci eviteremmo di doverci reinventare quello che altri hanno già definito.
Bene! Diamo un'occhiata ad un esempio di bibliografia descritta con XMLBiblio:
Listato 2. Esempio di Bibliografia
<?xml version="1.0" ?>
<biblio>
<autore>Hermann Hesse</autore>
<titolo>Narciso e Boccadoro</titolo>
<editore>Mondadori Editore</editore>
<anno_pubblicazione>1933</anno_pubblicazione>
<biblio>
Niente di complicato. Potremmo utilizzare questo linguaggio per inserire note bibliografiche in fondo ad una ricetta descritta con XMLRicette, come nel seguente esempio:
Listato 3. Ricetta con bibliografia
<?xml version="1.0" ?>
<ricetta>
<titolo>Pasta, aglio olio e peperoncino</titolo>
<autore>Anonimo</autore>
<ingredienti>
<ingrediente>200 gr. di spaghetti</ingrediente>
<ingrediente>uno spicchio di aglio</ingrediente>
<ingrediente>olio</ingrediente>
<ingrediente>un pizzico di peperoncino</ingrediente>
<ingrediente>sale</ingrediente>
<ingredienti>
<procedimento>
Far bollire dell'acqua in una pentola...
</procedimento>
<biblio>
<autore>Mario Rossi</autore>
<titolo>Della pasta e di altre delizie</titolo>
<editore>Chef Editore</editore>
<anno_pubblicazione>2002</anno_pubblicazione>
<biblio>
</ricetta>
Guardando meglio l'esempio, però, salta all'occhio un piccolo problemino: come il nostro linguaggio, anche XMLBiblio utilizza i tag <titolo>
e <autore>
, naturalmente per un contesto diverso. Ma come farà il parser a distinguere il tag <titolo>
di XMLBiblio dal tag <titolo>
di XMLRicette? Come possiamo risolvere il problema dei tag omonimi?
La soluzione
Il problema delle ambiguità che possono creare oggetti omonimi non è nuovo nell'informatica. Per fare qualche esempio, è lo stesso problema che si pone nell'estrazione di dati da due tabelle di un database che hanno campi con lo stesso nome.
Se ci pensiamo bene, in fondo, non è soltanto un problema dell'informatica. I nomi propri di persona hanno lo stesso potenziale problema. Se in un gruppo di persone ci sono due Andrea, come faccio ad individuarne uno per parlare di lui con un mio amico?
Semplice, direte voi. Basta citare anche il cognome! Ecco la soluzione: il cognome!
In termini tecnico-informatici il cognome è rappresentato dal namespace. Possiamo definire un namespace come un raggruppamento di nomi sotto un unico identificatore. Ritornando all'analogia delle persone, un namespace corrisponderebbe alla famiglia identificata dal cognome (nel senso che tutti i componenti di quella famiglia portano lo stesso cognome).
XML namespace
Individuata la soluzione da un punto di vista concettuale, vediamo come viene adottata in ambito XML e come applicarla al nostro documento d'esempio.
In un documento XML si fa riferimento ad un namespace utilizzando un attributo speciale, il fatidico xmlns, associato al root element, come nel seguente esempio:
Definizione di un namespace
<ricetta xmlns="namespaceRicetta">
Questo indica che l’elemento ricetta ed i suoi sottoelementi utilizzano i nomi definiti nel namespace identificato dall’identificatore namespaceRicetta. In altre parole, il "cognome" di <ricetta>
sarebbe namespaceRicetta
.
È 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 nostro problema di ambiguità può essere risolto, pertanto nel seguente modo:
Listato 4. Soluzione dell'ambiguità con i namespaces
<?xml version="1.0" ?>
<ricetta xmlns="namespaceRicetta">
<titolo>Pasta, aglio olio e peperoncino</titolo>
<autore>Anonimo</autore>
<ingredienti>
...
<biblio xmlns="namespaceBiblio">
<autore>Mario Rossi</autore>
<titolo>Della pasta e di altre delizie</titolo>
<editore>Chef Editore</editore>
<anno_pubblicazione>2002</anno_pubblicazione>
<biblio>
</ricetta>
Anche se in teoria sarebbe possibile utilizzare qualsiasi identificatore per un namespace, sarebbe opportuno utilizzare nomi univoci che evitino a loro volta omonimie tra namespace. Per questo motivo i namespace vengono identificati tramite URI (Uniform Resource Identifier); in particolare, è prassi comune utilizzare un URL come identificatore di un namespace, in modo che ci sia una corrispondenza biunivoca tra chi definisce un namespace ed il rispettivo nome a dominio.
Ad esempio, un possibile identificatore per il nostro linguaggio potrebbe essere:
Esempio di identificatore (URI)
<ricetta xmlns="https://www.html.it/XMLRicette">
Naturalmente non è assolutamente necessario che l'URL specificato corrisponda ad un documento pubblicato sul Web.
Namespace e prefissi
L'uso di un URL come identificatore di namespace può creare qualche problema di leggibilità, soprattutto quando vengono combinati insieme diversi linguaggi di markup.
In questi casi è opportuno utilizzare i prefissi come abbreviazione degli identificatori di namespace. Ad esempio, potremmo utilizzare la seguente abbreviazione nel nostro esempio:
Listato 5. Definizione degi prefissi al posto dei namespace
<?xml version="1.0" ?>
<xr:ricetta xmlns:xr="https://www.html.it/XMLRicette"
xmlns:xb="http://www.altrodominio.it/XMLBiblio">
<xr:titolo>Pasta, aglio olio e peperoncino</xr:titolo>
<xr:autore>Anonimo</xr:autore>
...
<xb:biblio>
<xb:autore>Mario Rossi</xb:autore>
<xb:titolo>Della pasta e di altre delizie</xb:titolo>
<xb:editore>Chef Editore</xb:editore>
<xb:anno_pubblicazione>2002</xb:anno_pubblicazione>
<xb:biblio>
</xr:ricetta>
Tramite l'attributo xmlns:xr
associamo al prefisso xr, scelto in modo del tutto arbitrario, il namespace https://www.html.it/XMLRicette
, mentre con xmlns:xb definiamo il prefisso xb per il namespace http://www.altrodominio.it/XMLBiblio
.
Con questo meccanismo ciascun elemento del documento è associato senza ambiguità al rispettivo namespace.
Namespace e XML Schema
Rimane un ultimo problema: come associare i tag di ciascun namespace al rispettivo XML Schema? In altre parole, come fa il parser a sapere con quale XML Schema dovrà validare un certo tag?
La soluzione è illustrata nel seguente esempio:
Listato 6. Istanza dello schema
<xr:ricetta xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xr="https://www.html.it/XMLRicette"
xmlns:xb="http://www.altrodominio.it/XMLBiblio"
xsi:schemaLocation="https://www.html.it/XMLRicette XMLRicette.xsd"
xsi:schemaLocation="http://www.altrodominio.it/XMLBiblio XMLBiblio.xsd">
L'attributo schemaLocation
del namespace http://www.w3.org/2001/XMLSchema-instance
ci consente di associare un namespace al rispettivo XML Schema.
Naturalmente in un documento XML possiamo soltanto fare riferimento ad un namespace. Il namespace vero e proprio viene definito nel relativo XML Schema che definisce la grammatica di un linguaggio XML-based. Per definire un namespace occorre utilizzare l'attributo targetNamespace come nel seguente esempio:
Definizione namespace usando «targetNamespace»
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.html.it/XMLRicette">
In questo modo si specifica che i tag definiti nello schema corrente costituiranno gli elementi del namespace indicato.
Conclusioni
Abbiamo visto in questo articolo le motivazioni dell'introduzione del concetto di namespace e il loro l'utilizzo all'interno di documenti XML. L'intento era di chiarire alcuni concetti di non facile lettura a chi si avvicina ad XML. Mi auguro che qualche nube si sia dissolta!