DTD (Segunda parte)

IDENTIFICADORES DE SISTEMA

Como ya dijimos anteriormente, es posible hacer una declaración de un DTD en un fichero externo. Un identificador de sistema nos permite especificar la localización de un fichero con declaraciones DTD. Está compuesto de dos partes: la palabra SYSTEM y una URI (identificador de un recurso). Observa los siguientes ejemplos:

<!DOCTYPE nombre SYSTEM "nombre.dtd" []> <!DOCTYPE nombre SYSTEM "file:///c:/nombre.dtd" []> <!DOCTYPE nombre SYSTEM "http://www.unsitio.com/recursoshumanos/nombre.dtd">

Estas son tres declaraciones válidas. Observa que en el último ejemplo no están los caracteres []. Esto es normal, ya que estos caracteres permiten definir opcionalmente un subconjunto de declaraciones internas. Este subconjunto de delaraciones opcional, conviviría con las declaraciones del fichero especificado.

IDENTIFICADORES PÚBLICOS

Existe otro mecanismo para localizar recursos DTD. Son los identificadores públicos. Observa el siguiente ejemplo:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">

¿Te suena? Empezamos con PUBLIC, seguido de un identificador específico del recurso. Con dicho identificador debería ser suficiente, ya que se refiere a una entrada de un catálogo. De acuerdo con la especificación XML, los identificadores públicos pueden tener cualquier formato, aunque comúnmente se usa un formato llamado FPI (Identificadores Formales Públicos). Su estructura es la siguiente:

-//Propietario//Descripción de clase//Idioma//Versión

La función de los identificadores públicos es similar a la de los namespaces. Pero los identificadores públicos no pueden usarse para combinar dos vocabularios en el mismo documento. Esto hace a los namespaces mucho más potentes que los identificadores públicos.

A continuación del identificador público, se puede incluir opcionalmente una URI del recurso dtd. Esto permite al procesador encontrar una copia del fichero dtd en caso de no poder resolver el identificador público (en realidad la mayoría de los analizadores sintácticos son incapaces de resolver los identificadores públicos). Cuando se incluye el identificador de sistema opcional, la palabra SYSTEM no es necesaria. La declaración sería como la siguiente:

DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

Observa que hay dos identificadores:

El identificador público: -//W3C//DTD XHTML 1.0 Strict//EN El identificador de sistema: http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd

NOTA: Muchos navegadores usan los identificadores públicos cuando identifican las versiones de un documento XHTML. Por ejemplo, muchas páginas XHTML usan el identificador -//W3C//DTD XHTML 1.0 Strict//EN para identificar el DTD asociado al documento. Cuando el navegador web lee el identificador, emplea una copia interna del DTD asociado, en vez de descargarse la copia desde la web. Esto permite a los navegadores evitar la descarga innecesaria del documento DTD y optimizar el análisis del documento.

EL FICHERO DTD EXTERNO

En el fichero DTD externo, sencillamente aparecen una a una las declaraciones ELEMENT. Por ejemplo, el siguiente podría ser un documento llamado "mihtml.dtd":

<!ELEMENT mihtml (c1 | parrafo)*> <!ELEMENT c1 (#PCDATA)> <!ELEMENT parrafo (#PCDATA|negrita)*> <!ELEMENT negrita (#PCDATA)>

En tal caso, el fichero mihtml.xml tendrá el siguiente aspecto (utilizando un identificador de sistema):

<?xml version="1.0"?> <!DOCTYPE mihtml SYSTEM "mihtml.dtd" []> <mihtml> <c2> Texto c1 </c2> <parrafo> Parrafo con <negrita> texto en negrita </negrita> y <cursiva> cursivas </cursiva> </parrafo> </mihtml>

Observa que la URI "mihtml.dtd" implica que el fichero dtd está ubicado en el mismo directorio que el documento mihtml.xml.

Ejercicio 2. Modifica el ejercicio anterior de modo que la declaración del DTD esté en un fichero separado, llamado contactos.dtd.

CARDINALIDAD

Anteriormente, vimos una declaración ELEMENT como la siguiente:

<!ELEMENT mihtml (c1 | parrafo)*>

Fue la primera aparición del concepto de cardinalidad. La cardinalidad de un elemento define cuantas veces paracerá dentro de un modelo de contenido. Cada elemento dentro un modelo de contenido puede tener un indicador que indica al analizador sintáctico cuantas veces aparecerá. Los DTDs permiten cuatro indicadores de cardinalidad:

  • Declaración sin indicador de cardinalidad: Cuando no se usa indicador de cardinalidad, indica que el element debe aparecer una y solo una vez. Este es el comportamiento por defecto usado en los modelos de contenido.
  • Declaración con el indicador "?": Indica que el elemento puede aparecer 0 o 1 vez.
  • Declaración con el indicador "+": Indica que el elemento puede aparecer 1 o más veces.
  • Declaración con el indicador "*": Indica que el elemento puede aparecer 0 o más veces.

Observemos la siguiente declaración:

<!ELEMENT persona (nombre+, apellido1, apellido2?)>

Hay muchas personas con un nombre compuesto. Los nombres compuestos pueden tener varias componentes; por ejemplo "Victor Antonio Manuel". No es muy común pero podría darse. Lo que es seguro que todo el mundo tiene al menos un nombre. Y puede que más de uno. Esto se ajusta exactamente al indicador de cardinalidad "+". Por eso aparece "nombre+". Por otro lado, en muchas culturas, una persona puede tener un solo apellido. Por lo que si estamos creando un DTD para un documento en el que aparezcan personas que puedan tener 1 o 2 apellidos, permitimos que el apellido2 pueda o no aparecer, lo que se ajusta al indicador de cardinalidad "?". Por eso aparece "apellido2?".

De acuerdo con la declaración anterior, los siguientes elementos serían correctos:

<persona> <nombre>Juan</nombre> <apellido1>García</apellido1> <apellido2>Pérez</apellido2> </persona>
<persona> <nombre>Pedro</nombre> <nombre>José</nombre> <apellido1>Gutiérrez</apellido1> </persona>

Si recordamos el ejemplo anterior de "contactos", tenía un problema: solo permitía un contacto, una dirección, etc.. Ahora podríamos redefinir el ejemplo del siguiente modo:

<!ELEMENT contactos (contacto*)> <!ELEMENT localización (dirección* | (latitud, longitud)*)>

Lo que esta declaración quiere decir, es que en un elemento "localización" válido, se pueden repetir, o bien un número indefinido de "dirección", o bien un número indefinido de coordeandas "(latitud, longitud)". Pero no pueden aparecer simultáneamente direcciones y coordenadas. Con esta declaración, el siguiente elemento sería válido.

<localización> <dirección>Ciudad-Intermedia, La Comarca, España</dirección> <dirección>Gotham City, Teruel, España</dirección> <dirección>Lamentos DF, Mordor, España </dirección> </localización>

NOTA: Observa la diferencia entre esta última definición y esta otra:

<!ELEMENT location (dirección | (latitud, longitud))*>

En este caso, pueden aparecer combinadas direcciones y coordenadas, siendo válido el siguiente elemento:

<localización> <dirección>Ciudad-Intermedia, La Comarca, España</dirección> <dirección>Gotham City, Teruel, España</dirección> <latitud>34.031892</latitud> <longitud>-117.207642</longitud> <latitud>-13.955059</latitud> <longitud>33.800125</longitud> </localización>

Este elemento no sería válido con la cardinalidad (dirección* | (latitud, longitud)*).

Ejercicio 3. Modifica el ejemplo de agenda de contactos anterior, para que sean válidos los siguientes elementos:

  • Al menos un contacto.
  • Una persona puede tener más de un nombre, y el segundo apellido es opcional.
  • Se pueden poner tantas localizaciones como se desee.
  • La descripción permite cualquier combinación de texto, "em", "strong" y "br".

Modifica los elementos del documento XML, de acuerdo con el DTD. Es decir, incluye más de un contacto, alguno de ellos con más de un nombre y un solo apellido, con varias localizaciones y descripciones medianamente complejas. Después valida tu documento.

Saludos.