TEMA 2.- DTD (Document Type Definition) 1. DTD DTD es un estándar que nos permite definir una gramática que deben cumplir nuestros documentos XML para considerarlos válidos. Una definición DTD para n documentos XML especifica: qué elementos pueden existir en un documento XML, qué atributos pueden tener éstos, qué elementos pueden o deben aparecer contenidos en otros elementos y en qué orden. <?xml version="1.0"?> <Receta> <Nombre>Tortilla de patatas</nombre> <Descripcion> La tradicional y típica tortilla de patatas, tal como la hacen todas las madres. </Descripcion> <Ingredientes> <Ingrediente> <Cantidad unidad="pieza">3</cantidad> <Item>Patata</Item> </Ingrediente> <Ingrediente> <Cantidad unidad="pieza">2</cantidad> <Item>Huevos</Item> </Ingrediente> <Ingrediente> <Cantidad unidad="litro">0.1</cantidad> <Item>Aceite</Item> </Ingrediente> </Ingredientes> <Instrucciones> <Paso> Pelar y cortar la patata en rodajas </Paso> <Paso> Poner aceite en una paella </Paso> <!-- Y así seguimos... --> </Instrucciones> </Receta> Veamos un posible DTD para la receta del ejemplo que nos definirá la forma que deben tener las recetas escritas en RecetaXML: <!-- DTD de ejemplo para RecetaXML --> <!ELEMENT Receta (Nombre, Descripcion?, Ingredientes?, Instrucciones?)> <!ELEMENT Nombre (#PCDATA)> <!ELEMENT Descripcion (#PCDATA)> <!ELEMENT Ingredientes (Ingrediente*)> IES MARE NOSTRUM LENGUAJES DE MARCAS Página 1 de 11
<!ELEMENT Ingrediente (Cantidad, Item)> <!ELEMENT Cantidad (#PCDATA)> <!ATTLIST Cantidad unidad CDATA #REQUIRED> <!ELEMENT Item (#PCDATA)> <!ATTLIST Item opcional CDATA 0 vegetariano CDATA si > <!ELEMENT Instructiones (Paso+)> <!ELEMENT Paso (#PCDATA)> De este documento DTD podemos inferir una descripción de las reglas de validez que sea un poco más legible: Una receta consta de un nombre (obligatorio), una descripción (opcional), unos ingredientes (opcionales) y unas instrucciones (opcionales). El nombre y la descripción pueden contener caracteres alfanuméricos (PCDATA corresponde a Parsed Character Data). Los ingredientes son una lista de elementos ingrediente. Un ingrediente consta de un ítem y la cantidad. La cantidad es un valor alfanumérico, teniendo la etiqueta un atributo, unidad que nos describe qué unidad de medida estamos utilizando. Un ítem de la receta consta del nombre (un valor alfanumérico) y puede tener dos atributos: opcional (si el ingrediente es o no obligatorio) y vegetariano (si el ingrediente es apto para vegetarianos). Las instrucciones de elaboración son una lista de pasos. Un paso consta de un texto alfanumérico descriptivo del paso. Convenciones sintácticas de DTD Como hemos visto, la sintaxis de DTD no resulta evidente a primera vista. Pese a ello, tampoco es excesivamente compleja. El primer paso para entenderla es disponer de las definiciones y usos de los diferentes símbolos usados, que podemos ver en la tabla siguiente: Símbolo Descripción ( ) Los paréntesis agrupan subetiquetas <!ELEMENT Ingrediente (Cantidad,Item)>, Ordenación exacta de los elementos (Nombre, Descripcion?, Ingredientes?, Instrucciones?) Uno sólo de los elementos indicados (Cocer Freir) Si no indicamos nada los elementos aparecen una sola vez (Cantidad, Item) + Una o más veces Paso+? Elemento opcional Instrucciones? * Cero o más veces Ingrediente* #PCDATA Parsed Character Data <!ELEMENT Item (#PCDATA)> PCDATA es texto que será analizado por el parser. El texto será examinado por el parser para entidades y etiquetas. Estos datos no deben contener ningún &, <, >, caracteres, que deben ser representados por el & < > respectivamente. IES MARE NOSTRUM LENGUAJES DE MARCAS Página 2 de 11
2. Declaración de tipos de elementos En el DTD hay que incluir la declaración de cada elemento que forma parte del documento. Ej.: <!ELEMENT Receta (Nombre, Descripcion?, Ingredientes?, Instrucciones?)> Define la etiqueta Receta, especificando qué contienen las subetiquetas: Nombre, Descripción, Ingredientes e Instrucciones, y agregando que estas tres últimas son opcionales (como indica el símbolo?). La definición de ELEMENT es la siguiente: <!ELEMENT nombre categoría> <!ELEMENT nombre (contenido)> 2.1. Elementos vacíos Se declaran especificando la palabra EMPTY. <!ELEMENT nombre EMPTY> Este elemento nombre en XML se usaría así: <nombre /> 2.2. Elementos que solo contienen caracteres (datos) Los elementos que sólo contendrán datos alfanuméricos se declaran usando #PCDATA entre paréntesis. <!ELEMENT nombre (#PCDATA)> En la declaración se especifica con #PCDATA. <!ELEMENT first (#PCDATA)> <!ELEMENT last (#PCDATA)> Atendiendo a esta definición el código '<first>john</first><last>doe</last>' sería válido ya que hemos utilizado los elementos 'first' y 'last' que hemos definido que solo contienen datos (texto). 2.3. Elementos con subelementos (secuencias) Se distinguen dos tipos de relación entre los elementos hijos. Secuencias o alternativos. Secuencias: Los elementos con uno o más hijos se definen con el nombre de los elementos hijos entre paréntesis: <!ELEMENT nombre (hijo1)> <!ELEMENT nombre (hijo1, hijo2,...)> Ej.: <!ELEMENT mensaje (remitente, destinatario, asunto, cuerpo)> <!ELEMENT coche (marca, matricula, color)> Los hijos que se declaran como una secuencia de elementos separados por comas deben aparecer en el mismo orden en el documento. Los elementos hijo también deben declararse en el documento DTD. Estos elementos hijo pueden, a su vez, tener elementos hijo. La declaración completa de coche sería entonces: IES MARE NOSTRUM LENGUAJES DE MARCAS Página 3 de 11
<!ELEMENT coche (marca, matricula, color)> <!ELEMENT marca (#PCDATA)> <!ELEMENT matricula (#PCDATA))> <!ELEMENT color (#PCDATA)> Alternativos: Cuando el elemento contiene uno y solo uno de los elementos hijos especificados. Ej.: <!ELEMENT persona (física jurídica)> Cardinalidad de las ocurrencias de elementos Para especificar cuántas veces aparece cada elemento hijo utilizamos un carácter que indique el factor de repetición: El carácter * : el elemento o grupo de elementos puede repetirse 0 o más veces. El carácter? : el elemento o grupo de elementos puede aparecer 0 o 1 veces. El carácter + : el elemento o grupo de elementos puede repetirse 1 o más veces. Por defecto, si no ponemos nada, el elemento debe aparecer una vez. La siguiente declaración nos indica que el elemento hijo sólo puede ocurrir una vez dentro del elemento padre: <!ELEMENT nombre (hijo)> Si deseamos que el elemento hijo aparezca más de una vez y como mínimo una vez: <!ELEMENT nombre (hijo+)> Si deseamos que pueda aparecer cualquier número de veces (incluyendo la posibilidad de que no aparezca ninguna): <!ELEMENT nombre (hijo*)> Si sólo deseamos que pueda aparecer una vez, pero que no sea obligatorio: <!ELEMENT nombre (hijo?)> Ejemplo: <!ELEMENT elem (a, (b c)*, d+, e?> De acuerdo a esta declaración las siguientes expresiones serían válidas: <elem><a></a><d></d><elem> <elem><a></a><d></d><d></d><e></e><elem> <elem><a></a><b></b><d></d><elem> <elem><a></a><c></c><b></b><c></c><d></d><elem> 2.4. Elementos con contenido mixto. Este caso no suele utilizarse en XML. El formato de esta declaración es muy rígido: Siempre en primer lugar PCDATA, una lista alternativa, no se puede aplicar caracteres de repetición a los elementos hijos y debe especificarse obligatoriamente el carácter de repetición * a todo el grupo. <!ELEMENT nombre (#PCDATA a b c)*> IES MARE NOSTRUM LENGUAJES DE MARCAS Página 4 de 11
2.5. Declaración de atributos. Una declaración de atributo tiene la sintaxis siguiente: <!ATTLIST nombre-elemento nombre-atributo tipo-atributo valor-atributo> DTD ejemplo: <!ATTLIST pago tipo CDATA "cheque"> XML ejemplo: <pago tipo="cheque" /> Cada uno de los distintos atributos debe declararse en el DTD. <!ATTLIST elemento atrib1 atrib2 atrib3 > <!ATTLIST elemento atributo tipo-atributo valor-defecto> Puede haber múltiples definiciones de listas de atributos para un mismo elemento. Pero si se declara varias veces el mismo atributo solo prevalece el primero. Un ejemplo de uso sería: <!ATTLIST pago metodo CDATA contra-reembolso > Y su uso en XML: <pago metodo= contra-reembolso /> El tipo de atributo debe ser uno de los de la lista: Valor Descripción CDATA El valor son caracteres alfanuméricos (v1 v2..) El valor será uno de la lista explicitada ID El valor será un identificador único IDREF El valor es el ID de otro elemento IDREFS El valor es una lista de ID otros elementos NMTOKEN El valor es un nombre XML válido NMTOKENS El valor es una lista de nombres XML válidos ENTITY El valor es una entidad ENTITIES El valor es una lista de entidades NOTATION El valor es el nombre de una notación xml: El valor es un valor XML predefinido 2.5.1. Atributos CDATA y NMTOKEN El tipo de atributos CDATA consiste en una cadena de caracteres. Esta cadena puede incluir cualquier carácter a excepción de los caracteres especiales, incluidos los espacios en blanco. <!ATTLIST coche color CDATA>. La propiedad color puede tomar cualquier valor. Si pretendemos limitar el tipo de caracteres que pueden aparecer como valor en el atributo, debemos utilizar el tipo NMTOKEN. Éste solo permite que aparezcan los mismos caracteres que utilizamos para definir elementos y atributos. <!ATTLIST coche color NMTOKEN>. La propiedad color puede tomar solo valores que contengan letras, dígitos, puntos, guiones y subrayados. Deben comenzar por letra y no pueden contener espacios en blanco. IES MARE NOSTRUM LENGUAJES DE MARCAS Página 5 de 11
Existe también la posibilidad de utilizar el tipo NMTOKENS, esto indica que el atributo contendrá una lista de cadenas de tipo NMTOKEN. <ATTLIST coche color NMTOKENS>. La propiedad color será una lista de NMTOKENS. Por ejemplo <coche color= blanco negro gris > 2.5.2. Atributos enumerados Se usan cuando el valor del atributo está restringido a un conjunto de valores. Se usa el carácter para separar los valores. <!ATTLIST coche color (blanco negro gris)> La propiedad color solo puede tomar los valores blanco, negro o gris. 2.5.3. Atributos ID e IDREF Es frecuente que algunos elementos tengan algún valor que los identifica de forma unívoca. Cuando un elemento contiene una propiedad de este tipo hay que asegurarse que esta no se repite en otro elemento. Incluso con elementos diferentes. La sintaxis es la siguiente: <!ATTLIST coche matricula ID> De esta forma nos aseguramos que en todo el documento XML no habrá otro elemento con un identificador igual. El valor del atributo identificador debe seguir las mismas reglas que los nombres de atributos y elementos. Además como es un identificador único permite que otros elementos puedan hacer referencia a él. Para ello pueden utilizar el tipo IDREF. Los valores que puede tomar un atributo IDREF son el conjunto de identificadores que están declarados en el documento. También podemos utilizar el tipo IDREFS que no es más que extender la definición de IDREF a una lista de valores. <!ATTLIST coche matricula ID> <!ATTLIST multa matricula IDREF> 2.5.4. Valores para los atributos Además del nombre y el tipo del atributo también se puede especificar cómo debe comportarse el parser ante la presencia o ausencia de cierto atributo en un elemento del documento. Existen cuatro posibles alternativas: El valor del atributo puede ser uno de los siguientes: Valor Valor #REQUIRED #IMPLIED #FIXED valor Descripción El valor por defecto del atributo. Si el atributo no está declarado toma este valor. El valor del atributo debe aparecer obligatoriamente en el elemento El atributo no tiene por qué ser incluido, es opcional El valor del atributo es fijo Si no se define ninguna de estas alternativas el atributo será por defecto opcional. Algunos casos especiales son por ejemplo los atributos de tipo ID que pueden ser opcionales u obligatorios pero no pueden tomar valores por defecto ni ser fijos. IES MARE NOSTRUM LENGUAJES DE MARCAS Página 6 de 11
En el siguiente ejemplo: <!ELEMENT pago EMPTY> <!ATTLIST pago metodo CDATA contra-reembolso > El siguiente XML se considera válido: <pago /> En este caso, donde no especificamos valor para método, éste contendrá el valor por defecto de contra-reembolso. Sintaxis de #IMPLIED En el siguiente ejemplo: <!ELEMENT pago EMPTY> <!ATTLIST pago metodo CDATA #IMPLIED > Validará correctamente el siguiente XML: <pago metodo= tarjeta /> <pago /> Usaremos, pues, #IMPLIED en aquellos casos en los que no queremos forzar al usuario a poner un atributo pero no queremos que tenga un valores por defecto. Sintaxis de #REQUIRED En el siguiente ejemplo: <!ELEMENT pago EMPTY> <!ATTLIST pago metodo CDATA #REQUIRED > Validará correctamente el siguiente XML: <pago metodo= tarjeta /> pero no validará: <pago /> Usaremos #REQUIRED en aquellos casos en los que no podemos proporcionar un valor por defecto, pero deseamos que el atributo aparezca y se le asigne algún valor. Ejemplos: <!ATTLIST coche matricula ID #REQUIRED> <!ATTLIST coche color CDATA #IMPLIED> <!ATTLIST coche color CDATA gris > <!ATTLIST coche marca FIXED Ford > IES MARE NOSTRUM LENGUAJES DE MARCAS Página 7 de 11
3. Declaración de entidades En general entidad se refiere a un objeto usado para guardar información y por ello necesariamente cada documento tiene al menos la entidad del propio documento. Permite guardar contenido que puede ser utilizado muchas veces y poder descomponer un documento grande en subconjuntos más manejables. Entidad interna. Es la más sencilla. Consiste en abreviaturas definidas en el DTD. Por ejemplo:<!entity derechos Copyright 2002 >. Al definir esta entidad, en el documento XML podemos utilizarla escribiendo &derechos;. El parser cambiará la entidad por el valor asignado. Entidad externa. El contenido no está dentro del DTD sino en cualquier otro sitio del sistema. Se hace referencia a su contenido mediante una URI precedida de la palabra SYSTEM o PUBLIC según proceda. La sintaxis es: <!ENTITY nombre SYSTEM URI > Ej.: <!ENTITY intro SYSTEM http://www.miservidor.com/intro.xml> Estas entidades externas permiten descomponer grandes archivos en unidades más pequeñas. 4. Vincular un DTD con un documento Para que un documento XML quede vinculado a un DTD determinado, tenemos dos opciones: incluir el DTD en el documento XML o usar una referencia externa al DTD. La primera opción es la más fácil de usar, pero la que presenta más inconvenientes, ya que aumenta el tamaño de los documentos XML y complica su mantenimiento, puesto que un cambio en el DTD implica revisar todos los documentos en los que lo hemos incluido. Entre la declaración XML y DOCTYPE solo se pueden insertar comentarios. Todo documento que deba ser validado debe contener una declaración DOCTYPE. <!DOCTYPE elemento_raíz origen ubicación [subconjunto interno]> Podemos referenciar un DTD externo al documento XML. Para ello disponemos de dos tipos de referencias posibles: públicas o privadas. Un ejemplo de referencia privada es el siguiente: <?xml version= 1.0?> <!DOCTYPE Receta SYSTEM receta.dtd > <Receta>... Y otro, usando ahora una referencia externa pública: <?xml version= 1.0?> <!DOCTYPE Receta PUBLIC -//W3C//DTD XHTML 1.0 STRICT/EN http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd > <Receta> IES MARE NOSTRUM LENGUAJES DE MARCAS Página 8 de 11
Que es la DTD pública utilizada para validar documentos XHTML estrictos. (Al fin y al cabo los documentos XHTML no son más que documentos HTML que utilizan DTD's para asegurar que el documento HTML es válido). Ejemplo de un documento XML con una declaración DTD interna: <?xml version="1.0"?> <!DOCTYPE mensaje [ <!ELEMENT mensaje (para,de,titulo,cuerpo)> <!ELEMENT para (#PCDATA)> <!ELEMENT de (#PCDATA)> <!ELEMENT titulo (#PCDATA)> <!ELEMENT cuerpo (#PCDATA)> ]> <mensaje> <para>jose</para> <de>maria</de> <titulo>recordatorio</titulo> <cuerpo>recuerda que el sábado iremos al cine</cuerpo> </mensaje> Cuando este documento sea analizado por un parser primero comprobará que está bien formado, luego comprobará que los elementos y atributos corresponden con la definición dada en el DTD. Para comprobar la validación vamos a guardar el contenido del documento anterior en un documento llamado msgdtd.xml. Y lo abriremos con la herramienta CookTop: Una vez abierto el documento si pulsamos sobre el botón señalado con la flecha nos debe aparecer en la parte inferior (barra de estado) el texto the XML document is valid. IES MARE NOSTRUM LENGUAJES DE MARCAS Página 9 de 11
Lo más utilizado es separar el documento XML del DTD. La declaración DTD irá en un fichero y el XML en otro fichero. Siguiendo con el ejemplo de los coches, lo lógico es que sea el portal quien diseñe el DTD con la información que necesita y cómo la necesita. Los concesionarios crean los documentos XML con la estructura dada y los mandan al portal, el cual, los valida antes de tratarlos. La sintaxis en este caso sería: <!DOCTYPE oferta SYSTEM http://www.servidor.com/oferta.dtd> De esta forma el que recibe el documento XML sabe con qué DTD debe validarlo antes de procesarlo. Siguiendo con el ejemplo de los mensajes vamos a separar del documento anterior la definición DTD del documento XML. Para ello creamos los dos ficheros siguientes: <?xml version="1.0" encoding= ISO-8859-1?> <!DOCTYPE mensaje SYSTEM "mensaje.dtd"> <mensaje prioridad="normal"> <para>jose</para> <de>maria</de> <titulo>recordatorio</titulo> <cuerpo>recuerda que el sábado iremos al cine</cuerpo> </mensaje> <!ELEMENT mensaje (para,de,titulo,cuerpo)> <!ATTLIST mensaje prioridad (urgente normal baja) #REQUIRED> <!ELEMENT para (#PCDATA)> <!ELEMENT de (#PCDATA)> <!ELEMENT titulo (#PCDATA)> <!ELEMENT cuerpo (#PCDATA)> Al primero le podemos llamar mensaje.xml y al segundo debemos llamarle mensaje.dtd que es el nombre utilizado en la declaración DOCTYPE. Es importante que los dos ficheros estén en el mismo directorio porque en la declaración DOCTYPE hemos escrito: SYSTEM mensaje.dtd. En caso de estar en diferente ubicación habría que especificarla SYSTEM../DTDS/mensaje.dtd por ejemplo. Podemos abrir el documento con Cooktop y validarlo. Buscar Cooktop en google y descargarlo. 5. Ejercicios 5.1. Libros y CD Escribir un DTD para los ejercicios de los coches, de la búsqueda de libros y el del CD del tema anterior. Realizar las modificaciones necesarias en los documentos XML para que se validen contra los DTD's creados. IES MARE NOSTRUM LENGUAJES DE MARCAS Página 10 de 11
IES MARE NOSTRUM LENGUAJES DE MARCAS Página 11 de 11