Introducció
El llenguatge XML, a diferència del llenguatge HTML o CSS, no incorpora normes en relació a quins elements estan disponibles o bé com s'ha d'utilitzar un determinat element. Així, en HTML, per a definir una llista podem utilitzar l'etiqueta ul o ol i, dins d'aquesta, definir cada un dels elements amb li . Utilitzant XML, podem definir una llista amb li i cada un dels elements amb ol o ul : tot i que això no tindria massa sentit!
Els documents DTD ens permeten definir quins són els elements vàlids i quina relació hi ha d'haver-hi entre aquests. Així, per exemple, puc crear un document XML en relació a un article:
<?xml version="1.0" ?>
<article nom="Caixa">
<material>Plàstic</material>
<color>Blau</color>
<mida>
<altura>40<unitats>cm</unitats></altura>
<amplada>30<unitats>cm</unitats></amplada>
<llargada>30<unitats>cm</unitats></llargada>
</mida>
</article>
o bé el document
<?xml version="1.0" ?>
<article codi="CB-403030">
<nom>Caixa</nom>
<quantitat>4</quantitat>
<preu>2.5
<moneda>E</moneda>
</preu>
</article>
En els dos casos estic parlant d'una caixa, però el significat d'un i altre document és molt diferent. Tot i que els dos documents XML són correctes, el seu significat és molt diferent. Segons quin sigui el propòsit pel qual es precisa la informació, hauré d'utilitzar un fitxer XML o l'altre.
Un altre problema que tenim amb els fitxers XML és en la seva interpretació. Així, per exemple, puc tenir dos documents XML que contenen la mateixa informació (interpretació humana) però a nivell informàtic són totalment diferents.
<?xml version="1.0" ?>
<article nom="Caixa">
<material>Plàstic</material>
<color>Blau</color>
<mida>
<altura>40<unitats>cm</unitats></altura>
<amplada>30<unitats>cm</unitats></amplada>
<llargada>30<unitats>cm</unitats></llargada>
</mida>
</article>
<?xml version="1.0" ?>
<article>
<nom>Caixa</nom>
<material>Plàstic</material>
<color>Blau</color>
<mida>
<altura uni="cm">40</altura>
<amplada uni="cm">30</amplada>
<llargada uni="cm">30</llargada>
</mida>
</article>
Necessitem un sistema per a eliminar les ambigüitats entre els documents XML. Els dos documents són vàlids (concepte well-formed), però a nivell informàtic es precisa saber quin format tindrà el document per tal de facilitar el seu tractament. Per a definir el format d'un document disposem del llenguatge DTD (Document Type Definition). Amb aquest llenguatge podem definir quina estructura i elements ha de tenir un document XML i poder-lo validar de forma ràpida. En el cas que el document XML no compleixi la definició descrita pel DTD, podrem descartar aquest document com o no vàlid.
Utilitzant DTD podem:
- Definir quina estructura ha de tenir un document XML, a nivell d'etiquetes i atributs.
- Definir quin és el vocabulari que es pot utilitzar dins un fitxer XML
Tipus DTD
- Intern: el DTD es declara dins el mateix document XML. Per tant en un únic arxiu hi ha el document XML i el document DTD.
- Extern: el DTD es defineix en un fitxer diferent al que conté el document XML.
Característiques DTD
Utilitzant DTD puc definir:
- Quins elements poden aparèixer en un document XML
- En quin ordre han d'aparèixer els elements
- Quins elements són obligatoris i quins són opcionals
- Quins atributs pot tenir un element
- Quins atributs són opcionals i quins són obligatoris
- Valors per defecte dels atributs
Avantatges DTD
- Cada usuari es pot definir la seva pròpia estructura de la informació. Aquesta estructura pot ser utilitzada per a la documentació del sistema.
- Podem utilitzar el DTD per a verificar que no hi ha errors d'estructura dins el nostre document XML.
Desavantatges DTD
- No incorpora el concepte d'espai de noms.
- Només contempla el tipus de dada string.
- Les possibilitats per a definir quantes vegades es pot repetir un determinat element són limitades.
Sintaxis document DTD
L'estructura general d'un document DTD intern és la que es mostra a continuació:
<!DOCTYPE element
[
declaració1
declaració2
........
]>
- DOCTYPE : defineix que és un document DTD
- element : nom del node arrel del document XML.
- declaració n : definició d'una característica que ha de complir el document XML
Un exemple senzill de declaració d'un document DTD intern per a un XML senzill seria el següent
<?xml version="1.0" ?>
<!DOCTYPE nom
[
<!ELEMENT nom (#PCDATA)>
]>
<nom>Miquel</nom>
En aquest cas declarem un DTD per a validar un document que té només un node, el node arrel. Aquest document només pot contenir una cadena de caràcters o bé ser un element buit.
<?xml version="1.0" ?>
<!DOCTYPE nom
[
<!ELEMENT nom EMPTY>
]>
<nom />
Validació documents XML
Per a validar els documents XML amb DTD intern podem utilitzar el servei de validació de XML online: https://www.xmlvalidation.com/. Simplement hem de carregar el fitxer .xml que conté l'especificació DTD o bé enganxar tot el document en l'àrea de text de la plana web. Posteriorment apretem el botó "Validate". En el cas que hi hagi errors, la plana web ens informarà de l'ubicació dels mateixos.
ELEMENT
Amb la directiva ELEMENT es referencia a una etiqueta del document XML. Per tant, cada etiqueta XML haurà de tenir associat una declaració amb ELEMENT en l'especificació DTD. Així, per exemple, el XML
<?xml version="1.0" ?>
<article />
observem en el XML anterior que hi ha una única etiqueta article . Per tant, el DTD ha de contenir una directiva ELEMENT amb referència a aquesta etiqueta article. Utilitzant un DTD intern, el document XML amb el seu DTD final seria:
<?xml version="1.0" ?>
<!DOCTYPE article
[
<!ELEMENT article EMPTY>
]>
<article />
Sintaxis ELEMENT
La sintaxis general per a ELEMENT és:
<!ELEMENT elementname (content)>
on elementname és el nom de l'etiqueta i content és el contingut de l'etiqueta. Observem un exemple de document XML més complex per a veure quin és el possible contingut d'una etiqueta XML.
<?xml version="1.0" ?>
<article codi="3129" >
<nom>Caixa</nom>
<material>Plàstic</material>
<color>Blau</color>
<mida>
<altura uni="cm">40</altura>
<amplada uni="cm">30</amplada>
<llargada uni="cm">30</llargada>
</mida>
<preu moneda="E">3.25
<dte>5%
<observacions>Per compres superiors a 20 unitats</observacions>
</dte>
</preu>
<venedor />
</article>
A partir del document XML anterior podem observar que una etiqueta XML pot contenir :
- Contingut buit (sense informació). Per exemple, l'etiqueta venedor és una etiqueta que no conté cap mena d'informació.
- Dades. Les etiquetes nom, material, color i observacions només contenen dades.
- Dades i atributs. Per exemple, l'etiqueta altura, amplada i llargada.
- Altres etiquetes. Per exemple, l'etiqueta mida
- Atributs i altres etiquetes. Per exemple, l'etiqueta article .
- Dades i altres etiquetes. Per exemple, l'etiqueta dte
- Dades, atributs i altres etiquetes. Per exemple, l'etiqueta preu
ELEMENT (content)
Per analitzar els valors possibles associats a content de l'etiqueta ELEMENT, segons la sintaxis associada a ELEMENT utilitzarem el següent document XML. Observem com en aquest document XML s'han eliminat els atributs. Tot i que poguem pensar que els dos documents contenen la mateixa informació la validació de les dades en aquest últim XML és molt més complexe; sobretot en relació a la validació de les unitats de mesura o a la moneda del preu.
<?xml version="1.0" ?>
<article>
<codi>3129</codi>
<nom>Caixa</nom>
<material>Plàstic</material>
<color>Blau</color>
<mida>
<altura>40cm</altura>
<amplada>30cm</amplada>
<llargada>30cm</llargada>
</mida>
<preu>3.25E
<dte>5%
<observacions>Per compres superiors a 20 unitats</observacions>
</dte>
</preu>
<venedor />
</article>
Etiqueta amb contingut buit EMPTY
Utilitzem la paraula clau EMPTY per a validar una etiqueta que no pot tenir contingut. Quan s'utilitza l'etiqueta EMPTY per a especificar que una etiqueta no ha de tenir contingut, no s'inclouen els parèntesis després del nom de l'etiqueta i, per tant, no es segueix la sintaxis específica d'ELEMENT.
<?xml version="1.0" ?>
<!DOCTYPE venedor
[
<!ELEMENT venedor EMPTY>
]>
<venedor />
Validació quan el contingut són dades #PCDATA
Per a forçar que una etiqueta només pugui contenir text, cal especificar-ho utilitzant la paraula clau #PCDATA. En aquest cas l'etiqueta no podrà contenir cap altre etiqueta, però sí qualsevol caràcter permès en XML.
<?xml version="1.0" ?>
<!DOCTYPE codi
[
<!ELEMENT codi (#PCDATA)>
]>
<codi>3129</codi>
Si l'element és de tipus #PCDATA i l'etiqueta no té contingut, el document XML també és vàlid. Tot i això, cal utilitzar EMPTY quan es vol crear un DTD per a generar un document XML amb una o vàries etiquetes sense contingut.
<?xml version="1.0" ?>
<!DOCTYPE codi
[
<!ELEMENT codi (#PCDATA)>
]>
<codi />
Altres etiquetes
Quan una etiqueta pot contenir altres etiquetes cal especificar com a content totes les etiquetes filles associades a la mateixa. Per exemple,
<?xml version="1.0" ?>
<!DOCTYPE mida
[
<!ELEMENT mida (altura,amplada,llargada)>
<!ELEMENT altura (#PCDATA)>
<!ELEMENT amplada (#PCDATA)>
<!ELEMENT llargada (#PCDATA)>
]>
<mida>
<altura>40cm</altura>
<amplada>30cm</amplada>
<llargada>30cm</llargada>
</mida>
En el XML anterior observem que declarem com a ELEMENT l'etiqueta mida i com a contingut les tres etiquetes filles: altura,amplada,llargada . Posteriorment declarem cada una d'aquestes etiquetes amb la seva informació.
Cal tenir en compte que quan s'especifiquen les etiquetes filles cal fer-ho amb l'ordre correcte. Així, per exemple, l'especificació <!ELEMENT mida (altura,llargada,amplada)> no és correcte ja que el segon fill en el document XML de mida és amplada i no llargada tal i com es determina en el DTD.
En canvi, quan es defineixen les etiquetes l'ordre no és obligat, tot i que per facilitar la lectura del document és preferible utilitzar el mateix ordre.
Per exemple, en aquest document, els ELEMENT no es declaren en el mateix ordre que les etiquetes, però, tot i això, el document és vàlid.
<?xml version="1.0" ?>
<!DOCTYPE mida
[
<!ELEMENT mida (altura,amplada,llargada)>
<!ELEMENT altura (#PCDATA)>
<!ELEMENT llargada (#PCDATA)>
<!ELEMENT amplada (#PCDATA)>
]>
<mida>
<altura>40cm</altura>
<amplada>30cm</amplada>
<llargada>30cm</llargada>
</mida>
Element ANY
El tipus ANY especifica que qualsevol contingut de l'etiqueta XML sobre el qual s'aplica el tipus serà vàlid. Per tant, no imposa cap restricció sobre l'etiqueta al qual s'aplica el tipus _ANY.
<?xml version="1.0" ?>
<!DOCTYPE mida
[
<!ELEMENT mida ANY>
<!ELEMENT altura (#PCDATA)>
<!ELEMENT llargada (#PCDATA)>
<!ELEMENT amplada (#PCDATA)>
]>
<mida>
<altura>40cm</altura>
<amplada>30cm</amplada>
<llargada>30cm</llargada>
</mida>
Com podem comprovar en el exemple, sí que cal especificar la resta d'etiquetes que contingui el document XML per tal que la validació amb el DTD sigui vàlida.
NOTA: Cal evitar l'ús del tipus ANY ja que aquest no imposa cap restricció al document XML.
DTD externs
Quan volem reutilitzar un DTD per a múltiples fitxers XML, podem crear un DTD extern i referenciar aquest DTD en el document XML. Veiem un exemple d'utilització d'un DTD extern
Fitxer: llibre.xml
<?xml version="1.0" ?>
<!DOCTYPE llibre SYSTEM "llibre.dtd">
<llibre>
<titol>Ender's game</titol>
<autor>Orson Scott Card</autor>
</llibre>
Fitxer: llibre.dtd
<!ELEMENT llibre (titol,autor)>
<!ELEMENT titol (#PCDATA)>
<!ELEMENT autor (#PCDATA)>
Quan s'executa la comanda xmllint utilitzem el paràmetre --noout per tal que no es mostri el contingut del fitxer XML. Amb el paràmetre --noout només es mostraran els errors de validació. A continuació es mostra l'execució de la comanda sense aquest paràmetre utilitzant els mateixos fitxers.
En el document XML en la instrucció DOCTYPE s'especifica el node arrel del document XML i a continuació de la paraula SYSTEM l'ubicació del fitxer DTD. En l'exemple anterior, el fitxer XML i el fitxer DTD estan ambdós en el mateix directori. En cas contrari s'hauria d'especificar la ruta a l'ubicació del fitxer DTD. En el següent exemple obtenim l'avís, warning: failed to load external entity "llibre.dtd" . En la imatge es pot veure el contingut del fitxer XML, observar la clausula DOCTYPE , del fitxer DTD i de l'ubicació dels fitxers.
Indicant la ruta per accedir al fitxer DTD observem que la validació del fitxer XML es fa de forma correcte.
Per a especificar la ruta del fitxer DTD s'aconsella utilitzar una ruta relativa, tot i que també hi ha la possibilitat de fer-ho amb una ruta absoluta. El problema de l'utilització d'una ruta absoluta és que cal reproduir la ruta en totes les màquines on hagi de residir.
SYSTEM vs PUBLIC
El tipus de DOCTYPE SYSTEM fa referència a un DTD privat. Podem utilitzar PUBLIC quan volem que el nostre DTD estigui a disposició d'altres usuaris: evidentment l'ubicació del fitxer DTD haurà de ser en un servidor accesible des d'Internet.
Per tal de poder validar els documents XHTML es disposen de diferents DTDs públics. En aquest cas, la declaració dependrà del tipus de XTHML que volguem definir: strict, transitional o frameset
Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
En la plana web https://validator.w3.org/ podem validar un document XML utilitzant els DTD definits de forma pública.
Operadors DTD
Els operadors ens permeten definir quines regles han de complir els documents XML. Suposem que una etiqueta XML s'ha de repetir un número indeterminat de vegades o que una etiqueta pot aparéixer de forma opcional: tant si apareix com no l'etiqueta volem que el document XML sigui considerat vàlid.
Operador ,
Com hem vist en els exemples anteriors, utilitzem l'operador "," per a indicar quins són els nodes fills d'una etiqueta composta.
Per exemple el DTD
Fitxer: llibre.dtd
<!ELEMENT llibre (titol,autor)>
<!ELEMENT titol (#PCDATA)>
<!ELEMENT autor (#PCDATA)>
Ens indica que un fitxer XML serà vàlid si el node arrel és llibre i aquest té dos fills: titol i autor . A més a més aquest ha de ser l'ordre en què constin els fills. Observem com l'únic operador que hem utilitzat és la "," i les seves implicacions són:
- Ordre en què han de constar els nodes.
- Obligatorietat a que hi hagin tots els nodes especificats.
- Cada node especificat només pot aparéixer 1 cop.
Operador +
Indica que l'element fill amb l'operador + ha d'aparéixer com a mínim una vegada
Per exemple, suposem el següent DTD per a representar un correu utilitzant XML.
Fitxer: mail.dtd
<!ELEMENT mail (from,to+,body)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT body (#PCDATA)>
Per a simplificar al màxim l'exemple s'ha reduït en gran mesura la informació continguda en el correu. El DTD s'anirà ampliant com a base per a posteriors exemples.
A continuació es detallen un parell de documents XML conformes al document DTD anterior.
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<body>Text</body>
</mail>
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<to>[email protected]</to>
<body>Text</body>
</mail>
El següent document XML NO ÉS VÀLID ja que no hi ha cap etiqueta to.
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<body>Text</body>
</mail>
La validació d'aquest document respecte al fitxer DTD anterior ens donarà l'error:
mail.xml:4: element mail: validity error : Element mail content does not follow the DTD, expecting (from , to+ , body), got (from body )
És important l'ubicació de l'operador + ja que canvia el sentit del DTD. En el nostre primer exemple, aquest operador l'hem ubicat al costat del node to . Per tant, expressa que l'etiqueta to ha d'aparéixer com a mínim una vegada.
En el següent document DTD s'ha canviat l'ubicació de l'operador + .
<!ELEMENT mail (from,to,body)+>
<!ELEMENT from (#PCDATA)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT body (#PCDATA)>
El canvi de l'ubicació de l'operador + fa que aquest canvii totalment de sentit. Així, per exemple, amb el document DTD anterior l'etiqueta mail ha de contenir els tres nodes: from, to, body, però aquest bloc de nodes es pot repetir més d'una vegada.
El següent document XML és vàlid amb el DTD anterior però també per a l'expressió (from,to+,body) utilitzada en el DTD original.
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<body>Text</body>
</mail>
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<body>Text</body>
<from>[email protected]</from>
<to>[email protected]</to>
<body>Text</body>
</mail>
El document XML anterior només és vàlid per a l'expressió (from,to,body)+ però no per a l'expressió (from,to+,body)
Operador *
Amb l'operador * s'especifica que l'element és opcional però pot estar present múltiples vegades. Seguint amb el DTD relacionat amb el correu electrònic podem veure un exemple d'utilització d'aquest operador.
Fitxer: mail.dtd
<!ELEMENT mail (from,to+,Bcc*,body)>
<!-- Bcc (Blind Carbon Copy) destinataris amb còpia oculta -->
<!ELEMENT from (#PCDATA)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT Bcc (#PCDATA)>
<!ELEMENT body (#PCDATA)>
A continuació s'ajunten un sèrie de documents XML corectes.
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<to>[email protected]</to>
<body>Text</body>
</mail>
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<Bcc>[email protected]</Bcc>
<body>Text</body>
</mail>
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<Bcc>[email protected]</Bcc>
<Bcc>[email protected]</Bcc>
<body>Text</body>
</mail>
Operador ?
Utilitzem l'operador ? per a indicar que un node és opcional. A diferència de l'operador * l'operador ? no permet que el node es repeteixi.
Fitxer: mail.dtd
<!ELEMENT mail (from,to+,Bcc*,subject?,body)>
<!-- Bcc (Blind Carbon Copy) destinataris amb còpia oculta -->
<!ELEMENT from (#PCDATA)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT Bcc (#PCDATA)>
<!ELEMENT subject (#PCDATA)>
<!ELEMENT body (#PCDATA)>
En el DTD anterior, la inclusió del subject del missatge és opcional. Però en el cas que hi consti, el missatge com a màixm podrà tenir un subject. Els següens documents XML són vàlids segons el DTD anterior.
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<Bcc>[email protected]</Bcc>
<Bcc>[email protected]</Bcc>
<body>Text</body>
</mail>
<?xml version="1.0" ?>
<!DOCTYPE mail SYSTEM "mail.dtd">
<mail>
<from>[email protected]</from>
<to>[email protected]</to>
<Bcc>[email protected]</Bcc>
<Bcc>[email protected]</Bcc>
<subject>Subject...</subject>
<body>Text</body>
</mail>
Operador |
Amb l'operador "|" indiquem diferents alternatives filles a un node fill. Suposem que volem guardar totes les incidències d'un sistema informàtic utilitzant fitxers XML. Volem utilitzar un DTD per a validar la informació dels nostres fitxers XML. Per a indicar la data podem utilitzar dia , mes i any (3 etiquetes) o bé només una etiqueta amb la data completa.
<?xml version="1.0" ?>
<!DOCTYPE incidencia SYSTEM "incidencia.dtd">
<incidencia>
<codi>32324</codi>
<descr>No hi ha connexió a la base de dades</descr>
<dia>10</dia><mes>3</mes><any>2018</any>
</incidencia>
<?xml version="1.0" ?>
<!DOCTYPE incidencia SYSTEM "incidencia.dtd">
<incidencia>
<codi>32324</codi>
<descr>No hi ha connexió a la base de dades</descr>
<data>10/3/2018</data>
</incidencia>
<!ELEMENT incidencia (codi,descr,(data | (dia,mes,any))>
<!ELEMENT codi (#PCDATA)>
<!ELEMENT descr (#PCDATA)>
<!ELEMENT data (#PCDATA)>
<!ELEMENT dia (#PCDATA)>
<!ELEMENT mes (#PCDATA)>
<!ELEMENT any (#PCDATA)>
Elements mixtes
Els elements mixtes són aquells que contenen dades i altres etiquetes. Per a validar aquest tipus d'element hem d'utilitzar una combinació de l'operador "|" i "*" .
<?xml version="1.0" ?>
<!DOCTYPE dte
[
<!ELEMENT dte (#PCDATA | observacions)*>
<!ELEMENT observacions (#PCDATA)>
]>
<dte>5%
<observacions>Per compres superiors a 20 unitats</observacions>
</dte>
Cal evitar l'ús dels elements mixtes, ja que no imposen restriccions en els documents XML. Així, per exemple, si s'elimina l'etiqueta observacions el codi XML continua essent vàlid segons el DTD especificat.
<?xml version="1.0" ?>
<!DOCTYPE dte
[
<!ELEMENT dte (#PCDATA | observacions)*>
<!ELEMENT observacions (#PCDATA)>
]>
<dte>5%</dte>