En la entrada anterior revisamos lo básico para comprender un archivo XML. En esta entrada continuaremos con un concepto no tan básico pero que también es bastante utilizado en XML: las DTD.
¿Qué es una DTD?
La definición de tipo de documento o DTD en inglés (Document Type Definition) nos sirve para definir la estructura que debe seguir la información en un archivo XML y poder concluir si este es válido según una serie de reglas que nosotros mismo definimos en función de nuestras necesidades, en otras palabras, se podría decir que es una definición gramatical que nos dirá si un XML es válido o no. Una DTD está escrita en su propio metalenguaje y no en XML.
Declaración de elementos
Siguiendo con los ejemplos de la nota anterior, a continuación tenemos una DTD para nuestro XML del negocio de videojuegos:
<?xml version="1.0" standalone="yes"?> <!-- Este es el inicio de la DTD --> <!DOCTYPE negocio [ <!ELEMENT negocio (videojuego+)> <!ELEMENT videojuego (titulo, desarrolladora)> <!ATTLIST videojuego estado (usado|nuevo) "nuevo"> <!ELEMENT titulo (PCDATA)> <!ELEMENT desarrolladora (PCDATA)> ]> <!-- Este es el fin de la DTD --> <negocio> <videojuego estado=”nuevo”> <titulo>Dragon Quest IX</titulo> <desarrolladora>Level 5</desarrolladora> </videojuego> </negocio>
Con el ejemplo anterior tenemos un primer acercamiento a las DTD. Este es el significado de cada sentencia:
<!DOCTYPE negocio [ … ]>
: Esta sección de la DTD define el elemento o etiqueta raíz del documento XML en el que se utilizará la definición, en este caso el elemento <negocio>.
<!ELEMENT negocio (videojuego+)>
: La etiqueta <!ELEMENT> nos permite definir la estructura de un elemento en el árbol XML. En este caso el elemento <negocio> (que también es el elemento raíz), contendrá elementos <videojuego> internos. Usando (videojuego+) indicamos que el elemento <videojuego> se debe incluir al menos una vez.
<!ELEMENT videojuego (titulo, desarrolladora)>
: Indica que el elemento <videojuego> tendrá 2 elementos internos, <titulo> y <desarrolladora>.
<!ATTLIST videojuego type (usado|nuevo) "nuevo">
: El elemento <!ATTLIST> nos sirve para definir el tipo y el valor de los atributos que permitirá un elemento en XML. En este caso <videojuego> tiene un atributo estado que puede tomar valores «nuevo» o «usado», siendo «nuevo» el valor por defecto.
<!ELEMENT titulo (PCDATA)>
y <!ELEMENT desarrolladora (PCDATA)>
: Estas sentencias especifican que los elementos <titulo> y <desarrolladora> tendrán caracteres revisados gramaticalmente. Si un texto no es revisado gramaticalmente, entonces puedes usar información dentro de él sin miedo a que XML “crea” que son parte de la estructura real del contenido; supongamos que usas CDATA en lugar de PCDATA en la etiqueta <dato> del siguiente ejemplo:
<dato><contenido></contenido></dato>
XML «sabrá» que <contenido></contenido> es el contenido de la etiqueta <dato> y no una etiqueta interna que deba ser definida. Si en su lugar hubiéramos utilizado PCDATA, <contenido></contenido> serían etiquetas inesperadas revisadas gramaticalmente que volverían inválido el XML.
Nos es posible especificar que las repeticiones de un elemento serán 0 o más ocurrencias:
<!ELEMENT elemento (subelemento*)>
O en su lugar, 0 o 1 ocurrencia:
<!ELEMENT elemento (subelemento?)>
Con ayuda de las definiciones anteriores podemos crear declaraciones mixtas como:
<!ELEMENT elemento (subelemento01*, subelemento02?, (subelemento03|subelemento04))>
Nota: esta declaración nos dice que <elemento> tendrá 0 o más hijos (o subelementos) <subeleemento01>; 0 o 1 hijos <subelemento02>; y, finalmente, un <subelemento03> o un <subelemento04>, pero no ambos.
En cambio, cuando queremos dar la libertad de tener elementos con cualquier contenido interno usamos ANY:
<!ELEMENT nombre ANY>
Si quisiéramos declarar un elemento o etiqueta vacía se utiliza EMPTY:
<!ELEMENT nombre EMPTY>
DTD externas
No es necesario que la DTD esté repetida en cada archivo XML. En su lugar podemos hacer referencia a un documento externo que la contenga. Para ello hacemos uso del atributo standalone en el prólogo. Desde nuestro XML tendríamos:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE negocio SYSTEM “negocio.dtd”> ... <!-- XML aquí-->
Definición de atributos
También es posible definir cuáles atributos tendrán los elementos y el tipo de valor que contendrán. La sintaxis es la siguiente:
<!ATTLIST elemento atributo tipo valor>
Si quisiéramos tener un atributo obligatorio en un elemento utilizamos #REQUIRED. En el siguiente ejemplo el elemento <videojuego> tendrá un atributo estado obligatorio:
<!ATTLIST videojuego estado CDATA #REQUIRED>
Si no es necesario que el elemento contenga el atributo pero se desea dejar la libertad de usarlo cuando sea necesario, para ello nos valemos de #IMPLIED como a continuación:
<!ATTLIST videojuego estado CDATA #IMPLIED>
Cuando conocemos el valor del atributo de antemano y queremos impedir el uso de otros valores usamos #FIXED:
<!ATTLIST videojuego estado CDATA #FIXED "Valor conocido">
Entidades
Como sucede con los caracteres especiales en XML los cuales usamos con ayuda de referencias a entidades (más información aquí), las DTD también nos permiten declarar nuestras propias entidades. Estas se declaran usando #ENTITY y, entre otras cosas, son muy útiles como atajos o valores constantes a las que podemos acceder dentro de un archivo XML de forma muy sencilla. Ejemplo dentro de la DTD:
<!ENTITY vendedor "El dueño de los videojuegos">
En el XML tendríamos que usar &vendedor; como a continuación:
<propietario>&vendedor; es quien posee los derechos de hacer con ellos lo que él desee</propietario>
Después del reemplazo de la referencia:
El dueño de los videojuegos es quien posee los derechos de hacer con ellos lo que él desee
Finalizando…
Espero que te haya servido lo analizado en esta entrada. En la siguiente continuaremos con las esquemas (schemas). Si tienes alguna duda, comentario o sugerencia, siéntete libre de compartirla en la sección de comentarios y la atenderé a la brevedad. Hasta la próxima, see ya!