Un documento XML deve rispettare determinate regole in modo da essere ben formato, ma nella maggior parte dei casi dovrà avere anche una struttura abbastanza fissa, in modo da non avere troppi tag in libertà. Prendiamo questo piccolo esempio:
<?xml version="1.0" ?> <classe nome="mammiferi"> <ordine nome="felini"> <famiglia nome="gatti"> <testo>Il mio gatto si chiama nuvola</testo> </famiglia> </ordine> <ordine nome="canidi"> <famiglia nome="cani"> <testo>Il mio cane si chiama birillo</testo> </famiglia> </ordine> </classe>
Abbiamo alcuni tag che prevedono attributi ed altri no. In questo tipo di documento possiamo cambiare il nome degli attributi, metterli con tag o senza, insomma possiamo fare quello che vogliamo. Questa estrema libertà genera confusione, soprattutto quando dobbiamo elaborare i documenti XML con dei parser. Abbiamo quindi bisogno di definire una grammatica per il linguaggio, basato su tag, che abbiamo inventato. Un documento XML che segue una determinata grammatica si chiama valido ed è possibile crearla tramite DTD ( Document Type Definition ).
Un DTD è un documento che descrive i tag utilizzabili e la loro relazione nei confronti della struttura, si basa sulla presenza di due pseudo-tag <!ELEMENT> e<!ATTLIST>: il primo definisce i tag utilizzabili nel documento, mentre il secondo definisce la lista di attributi utilizzabili per ciascun tag. Ad esempio, la definizione:
<!ELEMENT classe(ordine+)>
indica che il tag classe ha come sotto-elemento uno o più tag ordine.
- + – L’elemento è presente una o più volte.
- * – L’elemento è presente zero o più volte.
- ? – L’elemento è presente zero o una volta sola.
Ad esempio:
<!ELEMENT ordine(famiglia*, testo+)>
indica che il tag ordine contiene famiglia che può essere presente oppure no, mentre testo deve essere presente almeno una volta. Per la definizione dei tag che non contengono sotto-elementi dobbiamo distinguere il caso di tag vuoti, da tag che racchiudono del testo. Nel caso di tag vuoto abbiamo:
<!ELEMENT famiglia EMPTY>
mentre nel caso di tag con testo:
<!ELEMENT testo (#PCDATA)>
Per quanto riguarda la definizione degli attributi con <!ATTLIST> abbiamo:
<!ATTLIST classe nome CDATA #REQUIRED>
indica che il tag classe prevede un attributo nome che può avere un valore qualsiasi, l’indicazione #REQUIRED indica che la presenza dell’attributo è obbligatoria.
- #REQUIRED – La presenza dell’attributo è obbligatoria.
- #IMPLIED – Indica che l’attributo può essere omesso.
- #FIXED – Indica che il valore dell’attributo è fisso ed equivale al valore specificato subito dopo.
Se un attributo prevede dei valori alternativi predefiniti, è necessario specificarli al posto di CDATA. Vediamo un esempio di DTD riferito al nostro precedente esempio:
<!ELEMENT classe (ordine+)> <!ELEMENT famiglia (testo+)> <!ELEMENT testo (#PCDATA)> <!ATTLIST classe nome CDATA #REQUIRED> <!ATTLIST ordine nome CDATA #REQUIRED> <!ATTLIST famiglia nome CDATA #REQUIRED>
Una volta definito il linguaggio che vogliamo utilizzare, è possibile indicare il DTD nel file XML stesso:
…
<!DOCTYPE classe[…definizioni dtd…]>;
…
oppure è possibile inserire un riferimento al file esterno:
…
<!DOCTYPE classe SYSTEM “classe.dtd”>
…
In quest’ultimo caso nel nome del file è possibile inserire un percorso di rete o HTTP nel caso che il file risieda su una LAN o su web.
I DTD consentono quindi di limitare la libertà di utilizzo dei tag nel documento XML e ci sono dei parser che sono anche validanti con questo metodo. Ci sono poi altri meccanismi alternativi, anche migliori, che consentono di superare le limitazioni di DTD, stiamo parlando degli schemi XML di cui parleremo in un prossimo articolo.