Un DTD permite especificar la estructura básica de un documento XML. El siguiente par de ejemplos muestra lo que aparece cómo fragmentos de DTDs. El primero de ellos es una DTD que define la estructura básica del documento de ejemplo que vimos más arriba:
<!-- direccion.dtd --> <!ELEMENT direccion (nombre, calle, ciudad, estado, codigo-postal)> <!ELEMENT nombre (titulo? nombre, apellidos)> <!ELEMENT titulo (#PCDATA)> <!ELEMENT nombre (#PCDATA)> <!ELEMENT apellidos (#PCDATA)> <!ELEMENT calle (#PCDATA)> <!ELEMENT ciudad (#PCDATA)> <!ELEMENT estado (#PCDATA)> <!ELEMENT codigo-postal (#PCDATA)>
Este DTD define todos los elementos usados en el documento de ejemplo. Define tres cosas básicas:
Un elemento <direccion> que contiene un <nombre>, un <calle>, un <ciudad>, un <estado>, y un <codigo-postal>. Todos estos elementos deben aparecer y deben hacerlo en ese mismo orden.
Un elemento <nombre> contiene un elemento <titulo> opcional (la marca de pregunta indica que titulo es opcional), seguido de un elemento <nombre> y de un elemento <apellidos>.
Todos los demás elementos contienen texto. (#PCDATA indica datos de carácter; no pueden incluirse otros elementos dentro de estos.) Aunque son muy simples, las DTD aclaran que combinaciones de elementos son legales. Una documento de dirección postal que presente un elemento <codigo-postal> antes de un elemento <estado> no es legal, y ningún documento que no presente el elemento <apellidos> lo será. Además, hay que darse cuenta de que la sintaxis DTD es diferente de la sintaxis XML ordinaria. (Los documentos de Esquema XML, por el contrario, son XML ellos mismos, lo cual tiene algunas consecuencias interesantes.) A pesar de la sintaxis diferente de los DTDs se pueden seguir insertando comentarios ordinarios dentro de ellas.
Símbolos en los DTDs
Existen unos pocos símbolos usados en los DTDs para indicar cuantas veces (si es que lo hace) algo puede aparecer en un documento XML. Aquí mostramos algunos ejemplos junto a sus significados:
<!ELEMENT direccion (nombre, ciudad, estado)>
El elemento <direccion> debe contener un elemento <nombre>, un <ciudad>, y un <estado> en ese orden. Todos los elementos son obligatorios. La coma indica una lista de items.
<!ELEMENT nombre (titulo?, nombre, apellidos)>
Esto significa que el elemento <nombre> contiene un elemento <titulo> opcional, seguido obligatoriamente de un elemento <nombre> y de otro <apellidos>. La marca interrogación, indica que un item es opcional; Puede o no aparecer.
<!ELEMENT agenda (direccion+)>
Un elemento <agenda> contiene uno o más elementos <direccion>. Se pueden tener tantos elementos <direccion> como se necesiten, pero, al menos, debe existir uno. El signo mas (+) indica que un item debe aparecer al menos una vez, pero puede aparecer cualquier número de veces.
<!ELEMENT direcciones-privadas (direccion*)>
Un elemento <direcciones-privadas> contiene cero o más elementos <direccion>.
El asterisco indica que un item puede aparecer cualquier número de veces, incluyendo cero.
<!ELEMENT nombre (titulo?, nombre, (inicial-segundo-nombre | segundo-nombre)?, apellidos)>
Un elemento <nombre> contiene un elemento <titulo> opcional seguido de un elemento <nombre>, posiblemente seguido de un <inicial-segundo-nombre> o un elemento <segundo-nombre>, seguido de un elemento <apellidos>. En otras palabras, tanto <inicial-segundo-nombre> como <segundo-nombre> son opcionales y solamente se puede tener uno de los dos. Las barras verticales indican una lista de opciones; solo se puede escoger un item de la lista. Hay que notar que en este ejemplo se han usado paréntesis para agrupar ciertos elementos, y una marca de interrogación que afecta a todo el grupo.
<!ELEMENT nombre ((titulo?, nombre, apellidos) | (apellido, nombre-madre, apodo))> El elemento <nombre> puede contener una o más secuencias: Un elemento <titulo> opcional, seguido de un elemento <nombre> y otro <apellidos>; o un <apellido>, un <nombre-madre>, y un <apodo>.
Una palabra acerca de la flexibilidad
Antes de seguir, introduciremos una breve nota acerca del diseño de DTDs de cara a la flexibilidad. Considerando el ejemplo de dirección postal; lo hemos escrito claramente con la codificación postal de Estados Unidos en la mente. Si se quiere un DTD o esquema que defina reglas para otros tipos de direcciones, debería de añadir mucha más complejidad. El requerir un elemento <estado> puede tener sentido en Australia, pero no lo tendrá en Reino Unido. Una dirección canadiense podría ser manejada por el DTD de ejemplo de Document Type Definitions en la página 13, pero añadir un elemento <provincia> parece una idea mejor. Finalmente, hay que tener en cuenta que en muchos lugares del mundo, conceptos tales como título, primer nombre y segundo nombre no tienen sentido. Como punto final: si esta definiendo la estructura de un documento XML, debería ser tan prevenido en su DTD o esquema como si estuviese diseñando el esquema de la base de datos o la estructura de datos en una aplicación. Cuanto más requerimientos de futuro pueda prevenir, tanto más fácil y más barato le será el implementarlos más tarde.
Definición de atributos
Este tutorial introductorio no puede profundizar demasiado en cómo trabajan los DTDS, pero hay un tópico básico que sí cubriremos aquí: la definición de atributos. Se pueden definir atributos para los elementos que aparecen en su documento XML. Usando una DTD también se puede:
Definir qué atributos son obligatorios. Definir valores por defecto para los atributos Proporcionar una lista con los valores válidos para un atributo.
Supongamos que se quiere cambiar la DTD para hacer que estado sea un atributo del elemento <ciudad>. Se haría así:
<!ELEMENT ciudad (#PCDATA)> <!ATTLIST ciudad estado CDATA #REQUIRED>
Esto define el elemento <ciudad> como antes, pero el ejemplo revisado también usa una declaración ATTLIST para enumerar los atributos del elemento. El nombre ciudad dentro de la enumeración de atributos le dice al parser que esos atributos están definidos para el elemento <ciudad>. El nombre estado es el nombre del atributo y las palabras reservadas CDATA y #REQUIRED le dicen al parser que el atributo estado contiene texto y es obligatorio ( si fuese opcional, se indicaría con CDATA #IMPLIED). Para definir múltiples atributos para un elemento, se escribe un ATTLIST como este:
<!ELEMENT ciudad (#PCDATA)> <!ATTLIST
ciudad estado CDATA #REQUIRED codigo-postal CDATA #REQUIRED>
Este ejemplo define estado y codigo-postal como atributos del elemento <ciudad>. Finalmente, las DTDS permiten definir valores por defecto para los atributos y enumerar los valores válidos para un atributo: <!ELEMENT ciudad (#PCDATA)> <!ATTLIST ciudad estado CDATA (AZ|CA|NV|OR|UT|WA) "CA">
Este ejemplo indica que solo se soportan direcciones de los estados de Arizona (AZ), California (CA), Nevada (NV), Oregon (OR), Utah (UT), y Washington (WA), y que el valor por defecto es California. De esta manera se puede realizar una muy limitada forma de validación de los datos. Aunque es una función útil, es solo una pequeña parte de lo que se puede hacer con los esquemas XML.