Definición de Tipo de Documento
Después de la declaración XML,
el prologo del
documento puede incluir un DTD,
que nos permite especificar los tipos de etiquetas que se pueden incluir
en nuestro documento XML. Además de decirle al analizador de validación
qué etiquetas son validas,
y en qué disposición, un DTD le dice a los analizadores con validación y
sin validación donde se espera que vaya el texto, lo que permite al
analizador determinar si los espacios en blanco que ve son significantes
o ignorables.
Definiciones DTD Básicas
Por ejemplo, cuando estabamos analizando el visualizador de disapositivas,
vimos que el método characters fue invocado varias
veces antes y después de los comentarios y los elementos slide.
En dichos casos, los espacios en blanco que constituian el final de línea y
la identación rodeaban la marca. El objetivo era hacer leíble el documento
XML -- los espacios en blanco de ninguna forma eran parte del contenido del
documento. Para empezar a aprender sobre definiciones DTD, empecemos diciéndole
al analizador dónde se pueden ignorar los espacios en blanco.
Empezamos creando un fichero llamado slideshow.dtd.
Introducimos una declaración XML y un comentario para identificar el
fichero, como se ve abajo.
<?xml version='1.0' encoding='us-ascii'?>
<!-- DTD for a simple "slide show". -->
Luego, añadimos el texto en negrita de abajo para especificar que un
elemento slideshow contiene elementos
slide y nada más.
<!-- DTD for a simple "slide show". -->
<!ELEMENT slideshow (slide+)>
Como podemos ver, la etiqueta DTD empieza con <!
seguido por el nombre de etiqueta (ELEMENT).
Después del nombre de etiqueta viene el nombre del elemento que está
siendo definido (slideshow) y, entre paréntesis,
uno o más ítems que indican los contenidos válidos para ese elemento.
En este caso, la notación dice que un slideshow
consta de uno o más elementos slide.
Sin el signo más, la definición diría que un slideshow
consta de un único elemento slide. Aquí podemos ver
los cualificadores que podemos añadir a las definiciones de elementos.
| Cualificador |
Nombre |
Significado |
| ? |
Interrogación |
Opcional (cero o uno) |
| * |
Asterisco |
Cero o más |
| + |
Signo más |
Uno o más |
Podemos incluir varios elementos dentro de los paréntesis en una lista
separada por comas, y usar un cualificador en cada elemento para indicar
cuántos ejemplares de ese elemento podrían ocurrir. La lista separada
por comas dice qué elementos son válidos y el orden en el que pueden
ocurrir.
También podemos anidar paréntesis para agrupar varios ítems. Por ejemplo,
después de definir un elemento image, podríamos
declarar que cada image debe estar emparejada con
un elemento title en un slide
especificando ((image, title)+). Aquí el
signo más se aplica a la pareja image/title para
especificar que pueden ocurrir una o más parejas de los ítems especificados.
Definir Texto y Elementos Anidados
Ahora que le hemos dicho al analizador algo sobre donde
no se espera texto, veamos como decirle dónde si
puede ocurrir el texto. Añadimos el siguiente texto
en negrita para definir los elementos slide,
title, item, y
list.
<!ELEMENT slideshow (slide+)>
<!ELEMENT slide (title, item*)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT item (#PCDATA | item)* >
La primera línea dice que un slide consta de un
title seguido por cero o más elementos
item. Hast aquí nada nuevo. La siguiente línea dice
que un title consta completamente de un parsed
character data (PCDATA). Lo que se conoce como
"texto" en casi todo el mundo, pero hablando en XML, es llamado
"parsed character data". (Que se distingue de las secciones
CDATA, que contienen datos que no son analizados).
La almohadilla "#" que precede a PCDATA
indica que lo que sigue es una palabra especial, en vez de un nombre de
elemento.
La última línea presenta la barra vertical (|), lo
que indica una condición OR. En este caso, pueden
ocurrir un PCDATA o un item.
El asterisco del final dice que puede ocurrir cero o más veces sucesivas.
El resultado de está especificación es conocido como un
modelo de contenido
mixto, porque se puede interponer cualquier número de elementos
entre el texto. Dichos modelos siempre deben estar definidos previamente
con #PCDATA, un número de ítems alternativos separados
por barras verticales (|), y un asterisco
(*) al final.
Limitaciones de los DTDs
Sería bonito si pudieramos especificar que un item
contiene texto, o texto seguido por una o más listas de ítems. Pero esta
clase de especificaciones se convierte en dificil de conseguir en un DTD.
Por ejemplo, podríamos intentar definir un item como
este.
<!ELEMENT item (#PCDATA | (#PCDATA, item+)) >
Tan pronto como el analizador ve #PCDATA y una barra
vertical, requiere que el resto de la definición esté conforme al modelo
de contenido mixto. Esta especificación no lo hace, por eso obtenemos un
error que dice: Illegal mixed content model for 'item'. Found
( ..., donde el carácter 28 es el ángulo derecho que
termina la definición.
Intentar definir una doble definición del ítem tampoco funciona. Una
especificación como ésta:
<!ELEMENT item (#PCDATA) >
<!ELEMENT item (#PCDATA, item+) >
Produce unn aviso de "definición duplicada" cuando el analizador la
ejecuta. De echo, la segunda definición es ignorada. Por eso parece que
definir un modelo de contenido mixto (que permite que se interpongan
elementos item entre el texto) es lo mejor que
podemos hacer.
Además de las limitaciones del modelo de contenido mezclado mencionadas
arriba, no hay forma posterior de cualificar el tipo de texto que puede
ocurrir donde se ha especificado PCDATA. ¿Debería
contener sólo números? ¿Debería estar en formato fecha? o ¿posiblemente
en formato de moneda? No hay forma de decirlo en el contexto de un DTD.
Finalmente, observamos que el DTD no ofrece sentido de herencia. La
definición del elemento title se aplica igual a un
título de slide que a un título de
item. Cuando extendamos el DTD para permitir marcas
del estilo HTML además del texto normal tendría sentido restringir el
tamaño del título de un item comparándolo con un
título de slide,por ejemplo. Pero la única forma
de hacer esto sería darle a uno de ellos un nombre diferente, como
"item-title". La línea base es que este
tipo de herencia en el DTD nos fuerza a introducir un "árbol con guiones"
(o su equivalente) en nuestro espacio de nombres. Todas estas limitaciones
son motivos fundamentales detrás del desarrollo de los esquemas de
especificaciones estándards.
Valores de Elementos Especiales en el DTD
En vez de usar una lista de elementos entre paréntesis, la definición de
elemento podría usar uno de los dos valores especiales: ANY
o EMPTY. La especificación ANY
dice que el elemento podría contener otro elemento definido, o
PCDATA. Esta especificación se usa normalmente para
el elemento raíz en un documento XML de propósito general como el que
podríamos crear con un procesador de textos. Los elementos textuales
podrían ocurrir en cualquier orden en dicho documento, por eso, especificar
ANY tiene sentido.
La especificación EMPTY dice que el elemento no contiene
contenidos. Por eso el DTD para mensajes de email que nos permite "marcar"
el mensaje con <flag/> podría tener una línea
como ésta en el DTD.
<!ELEMENT flag EMPTY>
Referenciar el DTD
En este cado, la definición del DTD está en un fichero separado del documento
XML. Esto significa que tenemos que referenciarlo desde el documento XML, lo
que hace que el fichero DTD sea parte del
subconjunto
externo de la "Document Type Definition" (DTD) para el fichero
XML. Como veremos más adelante, podemos incluir partes del DTD dentro del
documento. Dichas definiciones constituyen el
subconjunto local
del DTD.
Para referenciar el fichero DTD que acabamos de crear, añadimos la línea
en negrita de abajo a nuestro fichero slideSample.xml.
<!-- A SAMPLE set of slides -->
<!DOCTYPE slideshow SYSTEM "slideshow.dtd">
<slideshow
De nuevo, la etiqueta DTD empieza con "<!".
En este caso, el nombre de la etiqueta, DOCTYPE, dice
que el documento es un slideshow, lo que significa que
el documento consta de un elemento slideshow y cualquier
cosa que haya dentro de él.
<slideshow>
...
</slideshow>
Esta etiqueta define el elemento slideshow como el
elemento raíz del
documento. Un documento XML debe tener exactamente un elemento raíz.
La etiqueta DOCTYPE ocurre después de la declaración
XML y antes del elemento raíz. El identificador SYSTEM
especifica la localización del fichero XML. Como no empieza con un prefijo
como http:/ o file:/, el path
es relativo a la localización del documento XML. ¿Recuerdas el método
setDocumentLocator? El analizador usa esta
información para encontrar el documento DTD, al igual que nuestra aplicación
podría encontrar un fichero relativo al documento XML. También se podría
utilizar un identificador PUBLIC para especificar el
fichero DTD usando un nombre único -- pero el analizador tendría que poder resolverlo.
La espeficación DOCTYPE también podría contener definiciones
DTD dentro del documento XML, en vez de referenciarlas a un fichero DTD externo.
Dichas definiciones estarían incluidas entre corchetes cuadrados, como esta.
<!DOCTYPE slideshow SYSTEM "slideshow1.dtd" [
...local subset definitions here...
]>
Nos aprovecharemos de esta facilidad más adelante cuando definamos algunas
entidades que pueden usarse en un documento.
| Nota:
Si se especifica una ID pública (URN)
en lugar de un ID de sistema (URL),
el analizador tendrá que poder resolverla a una dirección real para poder utilizarla.
Para hacer esto, el analizador puede configurarse con un
com.sun.xml.parser.Resolver usando el método
setEntityResolver del analizador, y la URN
puede asociarse con una URL local usando el método
registerCatalogEntry del
Resolver.
|