Inicio DTD (Document Type Definition)
Artículo
Cancelar

DTD (Document Type Definition)

Se recomienda la lectura de este artículo hasta la sección “7.5. Atributos de tipo IDREFS” incluida y la sección “12. Comentarios”. El resto de secciones pueden ser consultadas cuando sea necesario.

¿Qué es DTD?

DTD (Document Type Definition, Definición de Tipo de Documento) sirve para definir la estructura de un documento SGML o XML, permitiendo su validación.

  • SGML (Standard Generalized Markup Language, Lenguaje de Marcado Generalizado Estándar). Véase: http://www.w3.org/MarkUp/SGML/.
  • XML (eXtensible Markup Language, Lenguaje de Marcado eXtensible) es un lenguaje desarrollado por W3C (World Wide Web Consortium) que está basado en SGML.

En http://www.w3.org/TR/xml/ se puede consultar la W3C Recommendation de XML, en la cual se fundamenta este artículo, donde se explica -de forma introductoria a través de ejemplos- cómo escribir y utilizar DTD para validar documentos XML.

Un documento XML es válido (valid) cuando, además de estar bien formado, no incumple ninguna de las normas establecidas en su estructura.

¿Qué diferencia hay entre un documento XML válido y uno bien formado?

Existen otros métodos que también permiten validar documentos XML, como por ejemplo XML Schema o RELAX NG.

Declaración de tipo de documento

Una DTD se puede escribir tanto interna como externamente a un archivo XML. Ahora bien, en ambos casos hay que escribir una definición DOCTYPE (Document Type Declaration, Declaración de Tipo de Documento) para asociar el documento XML a la DTD. Asimismo, un archivo XML se puede asociar simultáneamente a una DTD interna y externa.

Documento XML asociado a una DTD interna

La sintaxis para escribir una DTD interna es:

1
<!DOCTYPE elemento-raíz [ declaraciones ]>

EJEMPLO En un documento XML se quiere guardar una lista de marcadores de páginas web, almacenando de cada uno de ellos su nombre, una descripción y su URL. Para ello, se puede escribir, por ejemplo, el archivo marcadores-con-dtd-interna.xml siguiente, que contiene una DTD interna:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE marcadores [
   <!ELEMENT marcadores (pagina)*>
   <!ELEMENT pagina (nombre, descripcion, url)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT descripcion (#PCDATA)>
   <!ELEMENT url (#PCDATA)>
]>

<marcadores>
   <pagina>
      <nombre>Abrirllave</nombre>
      <descripcion>Tutoriales de informática.</descripcion>
      <url>http://www.abrirllave.com/</url>
   </pagina>
   <pagina>
      <nombre>Wikipedia</nombre>
      <descripcion>La enciclopedia libre.</descripcion>
      <url>http://www.wikipedia.org/</url>
   </pagina>
   <pagina>
      <nombre>W3C</nombre>
      <descripcion>World Wide Web Consortium.</descripcion>
      <url>http://www.w3.org/</url>
   </pagina>
</marcadores>
  • Obsérvese que, en la DTD se ha indicado que marcadores es el elemento raíz del documento XML, el cual puede contener cero o más páginas. Para indicar esto último, se ha escrito: (pagina)*.
  • Escribiendo pagina (nombre, descripcion, url) se especifica que, cada elemento pagina tiene que contener tres elementos (hijos): nombre, descripcion y url.
  • Con #PCDATA (Parsed Character Data) escrito entre paréntesis () se indica que los elementos nombre, descripcion y url pueden contener texto (cadenas de caracteres) analizable por un procesador XML.

Al nombrar a los elementos pagina y descripcion no se han utilizado los caracteres (á) y (ó), respectivamente, para evitar posibles incompatibilidades con programas que puedan no reconocerlos.

Visualización del archivo “marcadores-con-dtd-interna.xml” en un navegador web

Al ver el archivo marcadores-con-dtd-interna.xml en un navegador web, como por ejemplo Google Chrome, se visualizará algo similar a:

Visualización del archivo "marcadores-con-dtd-interna.xml" en Google Chrome Visualización del archivo “marcadores-con-dtd-interna.xml” en Google Chrome

Como se puede observar, la DTD no se muestra en el navegador.

Por otro lado, para comprobar que el documento XML escrito en este ejemplo es válido se pueden utilizar distintos programas. Por ejemplo, véase cómo validar un documento XML asociado a una DTD con XML Copy Editor.

Documento XML asociado a una DTD externa

Existen dos tipos de DTD externa: privada y pública. Para las privadas se utiliza SYSTEM y para las públicas PUBLIC. La sintaxis en cada caso es:

1
<!DOCTYPE elemento-raíz SYSTEM "URI">
1
<!DOCTYPE elemento-raíz PUBLIC "identificador-público" "URI">
¿Qué es una URI?

URI (Uniform Resource Identifier, en español identificador uniforme de recursos) se emplea para todos los tipos de nombres y direcciones que se refieren a objetos internet tales como páginas, imágenes, videos, etc.

Un URI es por tanto una cadena de caracteres que se utilizan para identificar un recurso o un nombre en internet. Su propósito es permitir la interacción entre diferentes recursos en Internet y otro tipo de red.

En este caso, es la ubicación del DTD, ya sea local o en una ubicación pública en la web. Lo que proporciona una forma directa de acceder y recuperar el DTD.

Es posible especificar tanto FPI como URI en una declaración DOCTYPE. La combinación de FPI y URI permite que el DTD sea identificado de manera única mediante el FPI y, al mismo tiempo, permite su recuperación directa a través de la URI en caso de que sea necesario.

DTD externa privada - SYSTEM

EJEMPLO Si en un archivo llamado marcadores.dtd se escribiese la siguiente DTD:

1
2
3
4
5
<!ELEMENT marcadores (pagina)*>
<!ELEMENT pagina (nombre, descripcion, url)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT descripcion (#PCDATA)>
<!ELEMENT url (#PCDATA)>

El siguiente documento XML llamado marcadores-con-dtd-externa.xml, sería válido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE marcadores SYSTEM "marcadores.dtd">

<marcadores>
   <pagina>
      <nombre>Abrirllave</nombre>
      <descripcion>Tutoriales de informática.</descripcion>
      <url>http://www.abrirllave.com/</url>
   </pagina>
   <pagina>
      <nombre>Wikipedia</nombre>
      <descripcion>La enciclopedia libre.</descripcion>
      <url>http://www.wikipedia.org/</url>
   </pagina>
   <pagina>
      <nombre>W3C</nombre>
      <descripcion>World Wide Web Consortium.</descripcion>
      <url>http://www.w3.org/</url>
   </pagina>
</marcadores>

En este documento XML, haciendo uso de una DTD externa privada, se ha escrito una lista de marcadores de páginas web, guardando de cada uno de ellos su nombre, una descripción y su URL.

DTD externa pública - PUBLIC

EJEMPLO El siguiente documento XML está asociado a una DTD externa pública:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
   <head>
      <title>Título</title>
   </head>
   <body>
      <p>Párrafo</p>
   </body>
</html>

-//W3C//DTD XHTML 1.0 Strict//EN es un FPI (Formal Public Identifier, Identificador Público Formal). En este caso, el FPI es utilizado para identificar de manera única el DTD, y la URI proporciona la ubicación (única) para recuperar el DTD directamente si es necesario. Esto brinda flexibilidad y eficiencia en la validación del documento XML.

¿Para qué sirve un FPI?

El FPI proporciona información sobre la organización, el tipo de documento y el idioma. Este se puede utilizar para identificar el DTD, pero no proporciona la ubicación específica del archivo.

Cuándo utilizar una DTD interna o una DTD externa

Para validar más de un documento XML con la misma DTD, escribir esta en un archivo externo proporciona la ventaja de no tener que repetir la DTD internamente en cada documento XML.

En el caso de que la DTD solo se utilice para validar un único documento XML, la DTD es habitual escribirla internamente.

¿Cuándo es recomendable usar una DTD externa?

Uso combinado de DTD interna y externa en un documento XML

Para asociar un documento XML a una DTD interna y externa simultáneamente, se pueden utilizar las siguientes sintaxis:

1
<!DOCTYPE elemento-raíz SYSTEM "URI" [ declaraciones ]>
1
<!DOCTYPE elemento-raíz PUBLIC "identificador-público" "URI" [ declaraciones ]>

EJEMPLO Si en un documento XML llamado marcadores-con-dtd-interna-y-externa.xml se quiere almacenar una lista de marcadores de páginas web, guardando de cada uno de ellos su nombre, una descripción y su URL. En dicho documento se podría escribir:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE marcadores SYSTEM "marcadores.dtd" [
   <!ELEMENT marcadores (pagina)*>
   <!ELEMENT pagina (nombre, descripcion, url)>
]>

<marcadores>
  <pagina>
    <nombre>Abrirllave</nombre>
    <descripcion>Tutoriales de informática.</descripcion>
    <url>http://www.abrirllave.com/</url>
  </pagina>
  <pagina>
    <nombre>Wikipedia</nombre>
    <descripcion>La enciclopedia libre.</descripcion>
    <url>http://www.wikipedia.org/</url>
  </pagina>
  <pagina>
    <nombre>W3C</nombre>
    <descripcion>World Wide Web Consortium.</descripcion>
    <url>http://www.w3.org/</url>
  </pagina>
</marcadores>

De tal forma que, el contenido del archivo marcadores.dtd podría ser:

1
2
3
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT descripcion (#PCDATA)>
<!ELEMENT url (#PCDATA)>

Estructura de un documento XML

En una DTD se pueden declarar:

  • Elementos
  • Atributos
  • Entidades
  • Notaciones

Por tanto, un documento XML será válido si -además de no tener errores de sintaxis- cumple lo indicado en las declaraciones de elementos, atributos, entidades y notaciones, de la DTD a la que esté asociado.

Declaración de elementos

Para declarar un elemento en una DTD se utiliza la siguiente sintaxis:

1
<!ELEMENT nombre-del-elemento tipo-de-contenido>

En el tipo de contenido se especifica el contenido permitido en el elemento, pudiendo ser:

  • Texto, (#PCDATA).
  • Otros elementos (hijos).
  • Estar vacío, EMPTY.
  • Mixto (texto y otros elementos), ANY.

El contenido de un elemento puede ser texto - (#PCDATA)

EJEMPLO En el siguiente documento XML, el elemento ciudad puede contener cualquier texto (cadena de caracteres):

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ciudad [
   <!ELEMENT ciudad (#PCDATA)>
]>

<ciudad>Roma</ciudad>

Escribiendo #PCDATA (Parsed Character Data) entre paréntesis (), se ha indicado que el elemento ciudad puede contener una cadena de caracteres analizable.

Un elemento puede contener a otros elementos

EJEMPLO En el siguiente ejemplo, el elemento ciudad contiene a los elementos nombre y pais:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ciudad [
   <!ELEMENT ciudad (nombre, pais)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT pais (#PCDATA)>
]>

<ciudad>
  <nombre>Roma</nombre>
  <pais>Italia</pais>
</ciudad>

Un elemento puede no contener contenido (estar vacío) - EMPTY

EJEMPLO En la DTD interna del siguiente documento XML, se ha declarado el elemento mayor_de_edad como vacío, EMPTY. Por tanto, debe escribirse <mayor_de_edad/>:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona (nombre, mayor_de_edad, ciudad)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT mayor_de_edad EMPTY>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona>
   <nombre>Elsa</nombre>
   <mayor_de_edad/>
   <ciudad>Pamplona</ciudad>
</persona>

Los elementos vacíos no pueden tener contenido, pero sí pueden tener atributos.

¿Puede un elemento vacío tener atributos?

Un elemento puede definirse para contener contenido mixto - ANY

EJEMPLO En la DTD interna del siguiente documento XML, se ha indicado que el elemento persona puede contener texto y otros elementos, es decir, contenido mixto, ANY:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona ANY>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona>
   <nombre>Elsa</nombre> vive en <ciudad>Pamplona</ciudad>.
</persona>

Obsérvese que, por ejemplo, también sería válido el siguiente documento XML:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona ANY>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona>
   <nombre>Elsa</nombre> vive en Pamplona.
</persona>

O el siguiente:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona ANY>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona>
   <nombre>Elsa</nombre>
</persona>

Incluso, si el elemento persona estuviese vacío, el documento también sería válido:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona ANY>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona/>

Elementos vacíos - EMPTY

Para declarar un elemento vacío en una DTD, hay que indicar que su contenido es EMPTY. Un ejemplo de ello podría ser el elemento br del HTML, el cual sirve para hacer un salto de línea y no tiene contenido:

1
<!ELEMENT br EMPTY>

Dada la declaración anterior, en un documento XML el elemento br podría escribirse como:

1
<br/>

O también:

1
<br></br>

Por ejemplo, el siguiente documento XML sería válido:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE etiquetas_html [
   <!ELEMENT etiquetas_html (br)>
   <!ELEMENT br EMPTY>
]>

<etiquetas_html>
   <br/>
</etiquetas_html>

Un elemento vacío puede tener atributos

EJEMPLO Aunque un elemento se declare vacío, no pudiendo contener texto ni otros elementos, sí puede tener atributos:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE etiquetas_html [
   <!ELEMENT etiquetas_html (br)>
   <!ELEMENT br EMPTY>
   <!ATTLIST br descripcion CDATA #REQUIRED>
]>

<etiquetas_html>
   <br descripcion="Salto de línea"/>
</etiquetas_html>

En este ejemplo, para el elemento br se ha declarado el atributo descripcion de tipo CDATA (Character DATA), es decir, su valor puede ser una cadena de caracteres. Además, se ha indicado que el atributo es obligatorio escribirlo, #REQUIRED.

¿Por qué en los elementos usamos el tipo "(#PCDATA)" y en los atributos usamos el tipo "CDATA" si ambos se refieren a una cadena de texto?
  • PCDATA es un texto que será analizado por un analizador.
  • CDATA es un texto que no ser analizado por un analizador.

Pero… ¿Qué quiere decir esto?

El #PCDATA El modelo de contenido dice que un elemento puede contener texto sin formato. La parte “analizada” significa que el marcado (incluidos los PI, los comentarios y las directivas SGML) que contiene se analiza en lugar de mostrarse como texto en bruto. También significa que se sustituyen las referencias a entidades.

Otro tipo de modelo de contenido que permite contenidos de texto plano es CDATA . En xml, el modelo de contenido de los elementos no puede establecerse implícitamente en CDATA pero en SGML, significa que las referencias a marcas y entidades se ignoran en el contenido del elemento. En los atributos de CDATA sin embargo, se sustituyen las referencias a las entidades.

Elementos con cualquier contenido - ANY

Cuando en una DTD se quiere declarar un elemento que pueda contener cualquier contenido -bien sea texto, otros elementos o una mezcla de ambos- esto se puede hacer indicando que su contenido es de tipo ANY:

1
<!ELEMENT cualquier_contenido ANY>

EJEMPLO En el siguiente documento XML, el elemento cualquier_contenido contiene tres elementos texto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejemplo [
   <!ELEMENT ejemplo (cualquier_contenido)>
   <!ELEMENT cualquier_contenido ANY>
   <!ELEMENT texto (#PCDATA)>
]>

<ejemplo>
   <cualquier_contenido>
      <texto>Texto1</texto>
      <texto>Texto2</texto>
      <texto>Texto3</texto>
   </cualquier_contenido>
</ejemplo>

Fíjese que, definiendo la misma DTD, también sería válido el siguiente documento XML donde el elemento cualquier_contenido solo contiene texto:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejemplo [
   <!ELEMENT ejemplo (cualquier_contenido)>
   <!ELEMENT cualquier_contenido ANY>
   <!ELEMENT texto (#PCDATA)>
]>

<ejemplo>
   <cualquier_contenido>Texto1. Texto2. Texto3</cualquier_contenido>
</ejemplo>

Asimismo, el elemento cualquier_contenido podría contener una mezcla de texto y uno o más elementos.

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejemplo [
   <!ELEMENT ejemplo (cualquier_contenido)>
   <!ELEMENT cualquier_contenido ANY>
   <!ELEMENT texto (#PCDATA)>
]>

<ejemplo>
   <cualquier_contenido>Texto1<texto>Texto2</texto>Texto3</cualquier_contenido>
</ejemplo>

Por otra parte, si el elemento cualquier_contenido estuviese vacío, el documento XML seguiría siendo válido:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejemplo [
   <!ELEMENT ejemplo (cualquier_contenido)>
   <!ELEMENT cualquier_contenido ANY>
   <!ELEMENT texto (#PCDATA)>
]>

<ejemplo>
   <cualquier_contenido></cualquier_contenido>
</ejemplo>

En vez de <cualquier_contenido></cualquier_contenido>, también se puede escribir <cualquier_contenido/>.

Elementos con contenido de tipo texto - (#PCDATA)

Para declarar en una DTD un elemento que pueda contener texto analizable, se tiene que indicar que su contenido es (#PCDATA), (Parsed Character Data):

1
<!ELEMENT texto (#PCDATA)>

EJEMPLO En el siguiente documento XML, el elemento texto contiene caracteres:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejemplo [
   <!ELEMENT ejemplo (texto)>
   <!ELEMENT texto (#PCDATA)>
]>

<ejemplo>
   <texto>Este elemento solo contiene caracteres.</texto>
</ejemplo>

Ahora bien, el elemento texto podría estar vacío y el documento XML seguiría siendo válido:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejemplo [
   <!ELEMENT ejemplo (texto)>
   <!ELEMENT texto (#PCDATA)>
]>

<ejemplo>
   <texto></texto>
</ejemplo>

En vez de <texto></texto>, también se puede escribir <texto/>.

Secuencias de elementos

En una DTD, un elemento (padre) puede ser declarado para contener a otro u otros elementos (hijos). En la sintaxis, los hijos -también llamados sucesores- tienen que escribirse entre paréntesis () y separados por comas ,.

Elemento con varios hijos

EJEMPLO Para declarar un elemento (padre) que contenga tres elementos (hijos), se puede escribir:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!ELEMENT padre (hijo1, hijo2, hijo3)>
EJEMPLO En el siguiente documento XML, el elemento `persona` contiene a los elementos `nombre`, `fecha_de_nacimiento` y `ciudad`:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona (nombre, fecha_de_nacimiento, ciudad)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT fecha_de_nacimiento (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona>
   <nombre>Iker</nombre>
   <fecha_de_nacimiento>26-12-1997</fecha_de_nacimiento>
   <ciudad>Valencia</ciudad>
</persona>

A su vez, los hijos también pueden tener sus propios hijos. Así, el elemento fecha_de_nacimiento puede contener, por ejemplo, a los elementos dia, mes y anio:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona (nombre, fecha_de_nacimiento, ciudad)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT fecha_de_nacimiento (dia, mes, anio)>
   <!ELEMENT dia (#PCDATA)>
   <!ELEMENT mes (#PCDATA)>
   <!ELEMENT anio (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona>
   <nombre>Iker</nombre>
   <fecha_de_nacimiento>
      <dia>26</dia>
      <mes>12</mes>
      <anio>1997</anio>
   </fecha_de_nacimiento>
   <ciudad>Valencia</ciudad>
</persona>

Orden de los hijos de un elemento

En un documento XML, los elementos (hijos) de un elemento (padre), deben escribirse en el mismo orden en el que han sido declarados en la DTD.

EJEMPLO El siguiente documento XML no es válido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona (nombre, fecha_de_nacimiento, ciudad)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT fecha_de_nacimiento (dia, mes, anio)>
   <!ELEMENT dia (#PCDATA)>
   <!ELEMENT mes (#PCDATA)>
   <!ELEMENT anio (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
]>

<persona>
   <nombre>Iker</nombre>
   <fecha_de_nacimiento>
      <anio>1997</anio>
      <mes>12</mes>
      <dia>26</dia>
   </fecha_de_nacimiento>
   <ciudad>Valencia</ciudad>
</persona>

El documento no es válido porque los elementos sucesores (hijos) del elemento fecha_de_nacimiento no se han escrito en el mismo orden que en la DTD.

Cardinalidad de los elementos

En una DTD, para definir el número de veces que pueden aparecer los elementos de un documento XML, se pueden utilizar los operadores de cardinalidad mostrados en la siguiente tabla:

OperadorCardinalidadSignificado
? (interrogación)0-1El elemento es opcional, pudiendo aparecer una sola vez o ninguna.
* (asterisco)0-nEl elemento puede aparecer cero, una o más veces.
+ (signo más)1-nEl elemento tiene que aparecer, obligatoriamente, una o más veces.

Los elementos declarados en una DTD sobre los que no actúe ningún operador de cardinalidad, tendrán que aparecer obligatoriamente una única vez, en el o los documentos XML a los que se asocie.

Operador de cardinalidad “+” (signo más)

EJEMPLO En el siguiente documento XML, el elemento nombre tiene que aparecer una o más veces. En este caso, aparece tres veces:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE personas [
   <!ELEMENT personas (nombre+)>
   <!ELEMENT nombre (#PCDATA)>
]>

<personas>
   <nombre>Ana</nombre>
   <nombre>Iker</nombre>
   <nombre>Elsa</nombre>
</personas>

Si sobre nombre no actuase el operador (+) el documento no sería válido, ya que, el elemento personas solo tendría que contener un elemento nombre. En vez de (nombre+), también se puede escribir (nombre)+.

Operador de cardinalidad “*” (asterisco)

EJEMPLO En la DTD interna del siguiente documento XML, se ha indicado que el elemento nombre tiene que aparecer una única vez. Ahora bien, el elemento ingrediente tiene cardinalidad (0-n), por tanto, puede aparecer cero, una o más veces:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE receta_de_cocina [
   <!ELEMENT receta_de_cocina (nombre, ingrediente*)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT ingrediente (#PCDATA)>
]>

<receta_de_cocina>
   <nombre>Tortilla de patatas</nombre>
   <ingrediente>Huevo</ingrediente>
   <ingrediente>Patata</ingrediente>
   <ingrediente>Aceite</ingrediente>
   <ingrediente>Sal</ingrediente>
</receta_de_cocina>

Operador de cardinalidad “?” (interrogación)

EJEMPLO En la DTD del siguiente documento XML, la cardinalidad del elemento mayor_de_edad es (0-1), siendo opcional su aparición:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona (nombre, mayor_de_edad?)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT mayor_de_edad EMPTY>
]>

<persona>
   <nombre>Iker</nombre>
   <mayor_de_edad/>
</persona>

Así pues, el siguiente documento también es válido:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ELEMENT persona (nombre, mayor_de_edad?)>
   <!ELEMENT nombre (#PCDATA)>
   <!ELEMENT mayor_de_edad EMPTY>
]>

<persona>
   <nombre>Iker</nombre>
</persona>

Elementos opcionales

En la DTD asociada a un documento XML, se pueden declarar elementos que contengan elementos opcionales. Para ello, se utiliza el operador de elección, representado por una barra vertical (|).

Operador de elección “|” (barra vertical)

EJEMPLO En el siguiente documento XML el elemento articulo puede contener un elemento codigo o un elemento id; obligatoriamente uno de ellos, pero no ambos:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE articulo [
   <!ELEMENT articulo (codigo | id)>
   <!ELEMENT codigo (#PCDATA)>
   <!ELEMENT id (#PCDATA)>
]>

<articulo>
   <codigo>AF-33</codigo>
</articulo>

Operador de elección “|” y operador “*”

EJEMPLO En la DTD del siguiente documento XML se indica que el elemento articulos puede contener varios elementos codigo e id:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE articulos [
   <!ELEMENT articulos (codigo | id)*>
   <!ELEMENT codigo (#PCDATA)>
   <!ELEMENT id (#PCDATA)>
]>

<articulos>
   <codigo>AF-32</codigo>
   <id>3891</id>
   <codigo>AF-50</codigo>
   <codigo>AF-89</codigo>
</articulos>

Obsérvese que, con el operador *, en este ejemplo se ha indicado que el contenido del elemento articulos tiene cardinalidad (0-n). Por tanto, el elemento articulos puede:

  • Estar vacío.
  • Contener un elemento codigo.
  • Contener un elemento id.
  • Contener un elemento codigo y un elemento id.
  • Contener un elemento codigo y varios elementos id.
  • Contener un elemento id y varios elementos codigo.
  • Contener varios elementos codigo y varios elementos id.

Nótese también que, dentro del elemento articulos pueden aparecer elementos codigo e id en cualquier orden.

Operador de elección | en una secuencia de elementos

EJEMPLO En el siguiente documento XML, pueden aparecer cero o más elementos articulo que contengan un elemento codigo o un elemento id, y obligatoriamente un elemento nombre:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE articulos [
   <!ELEMENT articulos (articulo)*>
   <!ELEMENT articulo ((codigo | id), nombre)>
   <!ELEMENT codigo (#PCDATA)>
   <!ELEMENT id (#PCDATA)>
   <!ELEMENT nombre (#PCDATA)>
]>

<articulos>
   <articulo>
      <codigo>AF-47</codigo>
      <nombre>Martillo</nombre>
   </articulo>
   <articulo>
      <id>2056</id>
      <nombre>Destornillador</nombre>
   </articulo>
</articulos>

Secuencia de elementos en una lista de opciones

EJEMPLO En la DTD del siguiente documento XML se ha indicado que pueden aparecer cero o más elementos localidad. En el caso de aparecer, cada uno de ellos contendrá los elementos pais y ciudad, o alternativamente un elemento codigo_postal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE localidades [
   <!ELEMENT localidades (localidad)*>
   <!ELEMENT localidad ((pais, ciudad) | codigo_postal)>
   <!ELEMENT pais (#PCDATA)>
   <!ELEMENT ciudad (#PCDATA)>
   <!ELEMENT codigo_postal (#PCDATA)>
]>

<localidades>
   <localidad>
      <pais>España</pais>
      <ciudad>Valencia</ciudad>
   </localidad>
   <localidad>
      <codigo_postal>31015</codigo_postal>
   </localidad>
</localidades>

#PCDATA en una lista de opciones permite contenido mixto

EJEMPLO Al utilizar el operador de elección (|) en una DTD, si una de las opciones es #PCDATA, esta debe escribirse en primer lugar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE articulos [
   <!ELEMENT articulos (#PCDATA | codigo | id)*>
   <!ELEMENT codigo (#PCDATA)>
   <!ELEMENT id (#PCDATA)>
]>

<articulos>
   <id>8608</id>
   Teclado
   <codigo>AF-18</codigo>
   <codigo>AF-45</codigo>
   Disquetera
   <id>7552</id>
   <id>4602</id>
</articulos>

Fíjese que, el elemento articulos de este documento, puede contener contenido mixto, es decir, texto y otros elementos.

EJEMPLO Véase, en este último ejemplo, que el elemento provincia puede aparecer cero o más veces, pudiendo contener contenido mixto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE localidades [
   <!ELEMENT localidades (provincia*)>
   <!ELEMENT provincia (#PCDATA | ciudad | codigo_postal)*>
   <!ELEMENT ciudad (#PCDATA)>
   <!ELEMENT codigo_postal (#PCDATA)>
]>

<localidades>
   <provincia>
      Navarra
      <ciudad>Estella</ciudad>
      <codigo_postal>31015</codigo_postal>
      <ciudad>Tafalla</ciudad>
   </provincia>
   <provincia>
      Valencia
      <codigo_postal>46520</codigo_postal>
   </provincia>
</localidades>

Declaración de atributos

La sintaxis básica para declarar un atributo en una DTD es:

1
<!ATTLIST nombre-del-elemento nombre-del-atributo tipo-de-atributo valor-del-atributo>

¿Qué es un atributo?

Declaración de un atributo indicando un valor por defecto

EJEMPLO En la DTD del siguiente documento XML se ha indicado que el elemento f1 puede tener el atributo pais:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deportistas [
   <!ELEMENT deportistas (futbol | f1 | tenis)*>
   <!ELEMENT futbol (#PCDATA)>
   <!ELEMENT f1 (#PCDATA)>
      <!ATTLIST f1 pais CDATA "España">
   <!ELEMENT tenis (#PCDATA)>
]>

<deportistas>
   <f1 pais="Alemania">Sebastian Vettel</f1>
   <f1>Fernando Alonso</f1>
   <tenis>Rafael Nadal</tenis>
</deportistas>
  • Para el elemento f1, pais es un atributo definido de tipo CDATA (Character DATA), es decir, su valor será una cadena de caracteres.
  • Al no indicarse el país de Fernando Alonso, por defecto es España.
  • Para Sebastian Vettel, al atributo pais se le ha asignado Alemania, que es un valor distinto al valor-del-atributo, que por defecto es España.

Al visualizar el documento XML en un navegador web, se verá algo parecido a:

Visualización del archivo deportitas.xml en Google Chrome Visualización del archivo deportitas.xml en Google Chrome

Declaración de varios atributos en un elemento

EJEMPLO En la DTD del siguiente documento XML se ha indicado que el elemento f1 puede tener tres atributos (pais, fecha_de_nacimiento y equipo):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deportistas [
   <!ELEMENT deportistas (futbol | f1 | tenis)*>
   <!ELEMENT futbol (#PCDATA)>
   <!ELEMENT f1 (#PCDATA)>
      <!ATTLIST f1 pais CDATA "España">
      <!ATTLIST f1 fecha_de_nacimiento CDATA #IMPLIED>
      <!ATTLIST f1 equipo CDATA #REQUIRED>
   <!ELEMENT tenis (#PCDATA)>
]>

<deportistas>
   <f1 pais="Alemania" fecha_de_nacimiento="03/07/1987" equipo="Ferrari">Sebastian Vettel</f1>
   <f1 equipo="McLaren">Fernando Alonso</f1>
   <tenis>Rafael Nadal</tenis>
</deportistas>

Obsérvese que, en este ejemplo, el atributo equipo es obligatorio escribirlo, #REQUIRED. Mientras que, el atributo fecha_de_nacimiento es opcional, #IMPLIED.

En una DTD, cuando se declara más de un atributo para un elemento -como se ha hecho en este caso- no es necesario escribir varias veces <!ATTLIST, pudiéndose escribir, por ejemplo:

1
2
3
<!ATTLIST f1 pais CDATA "España"
             fecha_de_nacimiento CDATA #IMPLIED
             equipo CDATA #REQUIRED>

Tipos de declaración de atributos

En DTD, existen los siguientes tipos de declaración de atributos:

ValorSignificado
valor entre comillas dobles (") o simples (').El atributo tiene un valor por defecto.
#REQUIREDEl atributo es obligatorio escribirlo.
#IMPLIEDEl atributo es opcional escribirlo.
#FIXED valor entre comillas dobles (") o simples (').El valor del atributo es fijo.

En el apartado anterior de este tutorial “Atributos”, se muestra un ejemplo declaración de atributo con un valor por defecto.

Respecto a los otros tipos de declaración de atributos (#REQUIRED, #IMPLIED y #FIXED valor), en los siguientes apartados se muestran ejemplos:

  • Atributo obligatorio - #REQUIRED
  • Atributo opcional - #IMPLIED
  • Atributo con valor fijo - #FIXED valor
¿Puedo declarar un elemento como opcional dentro de la definición del propio elemento?

No.

Atributo obligatorio - #REQUIRED

EJEMPLO En la DTD interna del siguiente documento XML se ha declarado un atributo indicando que es obligatorio, es decir, #REQUIRED:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deportistas [
   <!ELEMENT deportistas (futbol | f1 | tenis)*>
   <!ELEMENT futbol (#PCDATA)>
   <!ELEMENT f1 (#PCDATA)>
      <!ATTLIST f1 pais CDATA #REQUIRED>
   <!ELEMENT tenis (#PCDATA)>
]>

<deportistas>
   <f1 pais="Alemania">Sebastian Vettel</f1>
   <f1>Fernando Alonso</f1>
   <tenis>Rafael Nadal</tenis>
</deportistas>

En este ejemplo, es obligatorio escribir el atributo pais en los elementos f1. Por tanto, aunque el documento XML está bien formado, habría que indicar el pais de Fernando Alonso para que fuese válido.

1
<f1 pais="España">Fernando Alonso</f1>

Por otra parte, fíjese que, de Rafael Nadal no es obligatorio indicar su país, ni se puede hacer.

Atributo opcional - #IMPLIED

EJEMPLO En una DTD, para especificar que un atributo es opcional escribirlo o no, hay que indicarlo mediante #IMPLIED:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deportistas [
   <!ELEMENT deportistas (futbol | f1 | tenis)*>
   <!ELEMENT futbol (#PCDATA)>
   <!ELEMENT f1 (#PCDATA)>
      <!ATTLIST f1 pais CDATA #IMPLIED>
   <!ELEMENT tenis (#PCDATA)>
]>

<deportistas>
   <f1 pais="Alemania">Sebastian Vettel</f1>
   <f1>Fernando Alonso</f1>
   <tenis>Rafael Nadal</tenis>
</deportistas>

En este caso, el atributo pais es opcional para los elementos f1 que aparezcan en el documento XML. Así pues, obsérvese que, aunque no se ha indicado el país de Fernando Alonso, el documento es válido.

Atributo con valor fijo - #FIXED valor

EJEMPLO Cuando en una DTD, se quiere declarar un atributo que tome un valor fijo, esto se puede hacer con #FIXED valor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deportistas [
   <!ELEMENT deportistas (futbol | f1 | tenis)*>
   <!ELEMENT futbol (#PCDATA)>
   <!ELEMENT f1 (#PCDATA)>
      <!ATTLIST f1 pais CDATA #FIXED "España">
   <!ELEMENT tenis (#PCDATA)>
]>

<deportistas>
   <f1 pais="España">Carlos Sainz</f1>
   <f1>Fernando Alonso</f1>
   <tenis>Rafael Nadal</tenis>
</deportistas>

Según la DTD de este documento XML, todos los elementos f1 que aparezcan tendrán el atributo pais con el valor España. Por tanto, no es necesario haberlo escrito para Carlos Sainz. De hecho, si se hubiese escrito otro valor, el documento no sería válido.

De modo que, para este caso, al visualizar el documento XML en un navegador web, se mostrará algo parecido a:

Visualización del archivo deportistas.xml con un atributo de valor fijo Visualización del archivo deportistas.xml con un atributo de valor fijo

Tipos de atributos

En DTD, existen los siguientes tipos de atributos:

TipoDescripción
CDATA(Character DATA) El valor son datos de tipo carácter, es decir, texto.
EnumeradoEl valor puede ser uno de los pertenecientes a una lista de valores escritos entre paréntesis () y separados por el carácter |.
IDEl valor es un identificador único.
IDREFEl valor es un identificador que tiene que existir en otro atributo ID del documento XML.
IDREFSEl valor es una lista de valores que existan en otros atributos ID del documento XML, separados por espacios en blanco.
NMTOKENEl valor es una cadena de caracteres, pudiendo contener letras minúsculas, letras mayúsculas, números, puntos ., guiones medios -, guiones bajos _ o el carácter dos puntos :.
NMTOKENSEl valor puede contener uno o varios valores de tipo NMTOKEN separados por espacios en blanco.
NOTATIONEl valor es el nombre de una notación.
ENTITYEl valor es el nombre de una entidad.
ENTITIESEl valor puede contener uno o varios valores de tipo ENTITY separados por espacios en blanco.
EspecialesExisten dos atributos especiales: xml:lang y xml:space.

Atributos de tipo CDATA

En una DTD, un atributo de tipo CDATA (Character DATA), es aquel cuyo valor puede ser una cadena de caracteres (texto).

EJEMPLO En la DTD del siguiente documento XML, el atributo pais del elemento ciudad ha sido declarado de tipo CDATA:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ciudades [
   <!ELEMENT ciudades (ciudad)*>
   <!ELEMENT ciudad (#PCDATA)>
      <!ATTLIST ciudad pais CDATA #REQUIRED>
]>

<ciudades>
  <ciudad pais="Italia">Roma</ciudad>
  <ciudad pais="Francia">París</ciudad>
  <ciudad pais="Alemania">Berlín</ciudad>
  <ciudad pais="">Viena</ciudad>
</ciudades>

Obsérvese que, el valor del atributo pais puede estar vacío.

Atributos de tipo enumerado

En una DTD, se puede declarar un atributo de tipo enumerado indicando que su valor puede ser uno de los pertenecientes a una lista de valores escritos entre paréntesis () y separados por el carácter |.

EJEMPLO En la DTD del siguiente documento XML, los valores posibles del atributo pais son ESP, FRA, ITA y ALE:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deportistas [
   <!ELEMENT deportistas (futbol | f1 | tenis)*>
   <!ELEMENT futbol (#PCDATA)>
   <!ELEMENT f1 (#PCDATA)>
      <!ATTLIST f1 pais (ESP | FRA | ITA | ALE) "ESP">
   <!ELEMENT tenis (#PCDATA)>
]>

<deportistas>
   <f1 pais="ALE">Sebastian Vettel</f1>
   <f1>Fernando Alonso</f1>
   <f1 pais="ESP">Carlos Sainz</f1>
   <tenis>Rafael Nadal</tenis>
</deportistas>

Véase que, en este caso, se ha especificado ESP como valor por defecto, siendo obligatorio que esté en la lista de valores escritos entre paréntesis ().

Al visualizar este documento en un navegador web, en pantalla se verá:

Visualización del archivo deportistas.xml con un atributo de tipo enumerado. Visualización del archivo deportistas.xml con un atributo de tipo enumerado.

Si se quiere definir el atributo pais obligatorio, habría que escribir:

1
<!ATTLIST f1 pais (ESP | FRA | ITA | ALE) #REQUIRED>

Por tanto, para Fernando Alonso se tendría que escribir:

1
<f1 pais="ESP">Fernando Alonso</f1>

Atributos de tipo ID

En una DTD, los atributos declarados ID son aquellos que solo pueden tomar un valor único (identificador) para cada elemento.

EJEMPLO En la DTD del siguiente documento XML, el atributo codigo del elemento f1 ha sido declarado de tipo ID:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE deportistas [
   <!ELEMENT deportistas (futbol | f1)*>
   <!ELEMENT futbol (#PCDATA)>
   <!ELEMENT f1 (#PCDATA)>
      <!ATTLIST f1 codigo ID #REQUIRED>
]>

<deportistas>
   <f1 codigo="ALO">Fernando Alonso</f1>
   <f1 codigo="VET">Sebastian Vettel</f1>
</deportistas>

Hay que tener en cuenta que:

  • Los valores de atributos ID, tienen que cumplir las mismas normas de sintaxis utilizadas para escribir nombres en XML.
  • Cada elemento escrito en un documento XML, solo puede tener un atributo ID.
  • En un documento XML, no pueden escribirse dos elementos que tengan el mismo valor en un atributo ID, aunque dicho atributo sea distinto.
  • Todo atributo declarado de tipo ID tiene que ser #IMPLIED (opcional) o #REQUIRED (obligatorio).

Atributos de tipo IDREF

En una DTD, los atributos declarados IDREF son aquellos cuyo valor tiene que existir en otro atributo ID del documento XML.

¿A qué equivaldría el atributo tipo IDREF en una base de datos relacional?

EJEMPLO En la DTD del siguiente documento XML, se indica que los elementos pelicula que se escriban, deben incluir el atributo direccion, cuyo valor estará asignado a un atributo ID de otro elemento del documento. En este caso, el valor estará asignado a un atributo coddir de un elemento director:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cine [
   <!ELEMENT cine (directores, peliculas)>
   <!ELEMENT directores (director)*>
      <!ELEMENT director (#PCDATA)>
         <!ATTLIST director coddir ID #REQUIRED>
   <!ELEMENT peliculas (pelicula)*>
      <!ELEMENT pelicula (#PCDATA)>
         <!ATTLIST pelicula direccion IDREF #REQUIRED>
]>

<cine>
   <directores>
      <director coddir="CE">Clint Eastwood</director>
      <director coddir="JC">James Cameron</director>
   </directores>
   <peliculas>
      <pelicula direccion="JC">Avatar</pelicula>
      <pelicula direccion="CE">Mystic River</pelicula>
      <pelicula direccion="JC">Titanic</pelicula>
   </peliculas>
</cine>

Obsérvese que, por ejemplo, para la película Titanic se ha indicado en su atributo direccion el valor JC, que es el valor del atributo coddir del director James Cameron.

En este documento XML, el atributo de tipo IDREF se ha definido obligatorio, #REQUIRED. Pero, a un atributo IDREF también se le puede especificar un valor por defecto, un valor fijo o que sea opcional escribirlo, #IMPLIED.

Atributos de tipo IDREFS

En una DTD, los atributos declarados IDREFS son aquellos cuyo valor puede ser una lista de valores que existan en otros atributos ID del documento XML.

EJEMPLO En la DTD del siguiente documento XML, se indica que el valor del atributo filmografia de un elemento director, puede ser una lista de valores de atributos ID. En este caso, una lista de valores escritos en el atributo codpel de los elementos pelicula que aparezcan en el documento XML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cine [
   <!ELEMENT cine (peliculas, directores)>
   <!ELEMENT peliculas (pelicula)*>
      <!ELEMENT pelicula (#PCDATA)>
         <!ATTLIST pelicula codpel ID #REQUIRED>
   <!ELEMENT directores (director)*>
      <!ELEMENT director (#PCDATA)>
         <!ATTLIST director filmografia IDREFS #REQUIRED>
]>

<cine>
   <peliculas>
      <pelicula codpel="P1">Avatar</pelicula>
      <pelicula codpel="P2">Mystic River</pelicula>
      <pelicula codpel="P3">The Terminator</pelicula>
      <pelicula codpel="P4">Titanic</pelicula>
   </peliculas>
   <directores>
      <director filmografia="P2">Clint Eastwood</director>
      <director filmografia="P1 P3 P4">James Cameron</director>
   </directores>
</cine>

Obsérvese que, los valores de la lista de valores de un atributo IDREFS, se escriben separados por un espacio en blanco.

¿Cómo se separan los diferentes IDREF dentro de un IDREFS?

Atributos de tipo NMTOKEN

En una DTD, los atributos declarados NMTOKEN son aquellos cuyo valor será una cadena de caracteres, pudiendo contener letras minúsculas, letras mayúsculas, números, puntos ., guiones medios -, guiones bajos _ o el carácter dos puntos :.

EJEMPLO En la DTD del siguiente documento XML, el atributo clave del elemento usuario ha sido declarado de tipo NMTOKEN:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE usuarios [
  <!ELEMENT usuarios (usuario)*>
  <!ELEMENT usuario (#PCDATA)>
  <!ATTLIST usuario clave NMTOKEN #REQUIRED>
]>

<usuarios>
  <usuario clave="123456789">Ana</usuario>
  <usuario clave="ab-c-d-fg">Iker</usuario>
  <usuario clave="A1_B2..C3">Elsa</usuario>
</usuarios>

En el valor de un atributo NMTOKEN no se pueden escribir espacios en blanco ni caracteres especiales, tales como: *, $, %, &, ?, @…

Atributos de tipo NMTOKENS

En una DTD, los atributos declarados NMTOKENS son aquellos cuyo valor puede contener uno o varios valores de tipo NMTOKEN separados por espacios en blanco.

EJEMPLO En la DTD del siguiente documento XML, el atributo codigos del elemento usuario ha sido declarado de tipo NMTOKENS:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE usuarios [
  <!ELEMENT usuarios (usuario)*>
  <!ELEMENT usuario (#PCDATA)>
  <!ATTLIST usuario codigos NMTOKENS #REQUIRED>
]>

<usuarios>
  <usuario codigos="1234 567 89">Ana</usuario>
  <usuario codigos="ab c-d fg">Iker</usuario>
  <usuario codigos="A1:B2">Elsa</usuario>
</usuarios>

Obsérvese que, los valores escritos en el atributo codigos, se escriben separados por espacios en blanco.

Atributos de tipo NOTATION

En una DTD, los atributos declarados NOTATION son aquellos cuyo valor puede ser el nombre de una notación.

EJEMPLO En la DTD del siguiente documento XML, se indica que los elementos animal que se escriban, deben incluir opcionalmente el atributo tipo_de_imagen, cuyo valor será una notación (gif, jpg o png):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version = "1.0" encoding="UTF-8"?>
<!DOCTYPE animales [
   <!ELEMENT animales (animal)*>
   <!ELEMENT animal (nombre)>
   <!ELEMENT nombre (#PCDATA)>
   <!ATTLIST animal
      imagen CDATA #IMPLIED
      tipo_de_imagen NOTATION (jpg | gif | png) #IMPLIED>

   <!NOTATION gif SYSTEM "image/gif">
   <!NOTATION jpg SYSTEM "image/jpeg">
   <!NOTATION png SYSTEM "image/png"> 
]>

<animales>
    <animal imagen="ballena-azul.gif" tipo_de_imagen="gif">
        <nombre>Ballena</nombre>
    </animal>
    <animal imagen="leon-dormido.png" tipo_de_imagen="png">
        <nombre>Leon</nombre>
    </animal>
</animales>

En este ejemplo, las notaciones gif, jpg y png son declaraciones de los tipos MIME (Multipurpose Internet Mail Extensions, Extensiones Multipropósito de Correo de Internet): image/gif, image/jpeg e image/png.

EJEMPLO En la DTD del siguiente documento XML, se indica que los elementos programa que se escriban, deben incluir obligatoriamente el atributo lenguaje, cuyo valor será una notación (csharp o java):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE programas [
   <!ELEMENT programas (programa)*>
   <!ELEMENT programa (#PCDATA)>
   <!ATTLIST programa lenguaje NOTATION (csharp|java) #REQUIRED>

   <!NOTATION csharp PUBLIC "CSharp 5.0">
   <!NOTATION java PUBLIC "Java 8.0">
]>

<programas>
   <programa lenguaje="java"><!-- Código fuente 1. --></programa>
   <programa lenguaje="java"><!-- Código fuente 2. --></programa>
   <programa lenguaje="csharp"><!-- Código fuente 3. --></programa>
</programas>

CSharp 5.0 y Java 8.0 son identificadores públicos.

Atributos de tipo ENTITY

En una DTD, los atributos declarados ENTITY son aquellos cuyo valor puede ser el nombre de una entidad.

¿Qué es una entidad?

Uso de ENTITY y NOTATION

EJEMPLO En la DTD del siguiente documento XML, se indica que los elementos animal que se escriban, tiene que incluir obligatoriamente el atributo imagen, cuyo valor será una entidad:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE animales [
   <!ELEMENT animales (animal)*>
   <!ELEMENT animal EMPTY>
   <!ATTLIST animal imagen ENTITY #REQUIRED>

   <!ENTITY ballena SYSTEM "ballena.gif" NDATA gif>
   <!ENTITY delfin SYSTEM "delfin.gif" NDATA gif>

   <!NOTATION gif SYSTEM "image/gif">
]>

<animales>
   <animal imagen="ballena"/>
   <animal imagen="delfin"/>
</animales>
  • En la DTD de este ejemplo se está indicando que los valores -datos- de las entidades (ballena y delfin) van a ser cargados desde una URI (Uniform Resource Identifier, Identificador Uniforme de Recurso). En este caso, se hace referencia a los archivos externos ballena.gif y delfin.gif.
  • Con NDATA (Notation Data) se ha asociado a las entidades ballena y delfin con la notación gif.
  • La notación gif es una declaración del tipo MIME image/gif.

Atributos de tipo ENTITIES

En una DTD, los atributos declarados ENTITIES son aquellos cuyo valor puede contener uno o varios valores de tipo ENTITY separados por espacios en blanco.

Uso de ENTITIES y NOTATION

EJEMPLO En la DTD del siguiente documento XML, el atributo imagenes del elemento grupos ha sido declarado de tipo ENTITIES:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE animales [
   <!ELEMENT animales (grupos)*>
   <!ELEMENT grupos EMPTY>
   <!ATTLIST grupos imagenes ENTITIES #REQUIRED>
   
   <!ENTITY ballena SYSTEM "ballena.gif" NDATA gif>
   <!ENTITY delfin SYSTEM "delfin.gif" NDATA gif>
   <!ENTITY elefante SYSTEM "elefante.gif" NDATA gif>
   <!ENTITY leon SYSTEM "leon.gif" NDATA gif>
   <!ENTITY oso SYSTEM "oso.gif" NDATA gif>

   <!NOTATION gif SYSTEM "image/gif">
]>

<animales>
   <grupos imagenes="ballena"/>
   <grupos imagenes="ballena delfin"/>
   <grupos imagenes="elefante leon oso"/>
   <grupos imagenes="ballena elefante"/>
</animales>
  • En la DTD de este ejemplo se está indicando que los valores -datos- de las entidades (ballena, delfin, elefante, leon y oso) van a ser cargados desde una URI (Uniform Resource Identifier, Identificador Uniforme de Recurso). En este caso, se hace referencia a los archivos externos ballena.gif, delfin.gif, elefante.gif, leon.gif y oso.gif.
  • Con NDATA (Notation Data) se ha asociado a las entidades ballena, delfin, elefante, leon y oso con la notación gif.
  • La notación gif es una declaración del tipo MIME image/gif.

Atributos especiales

En DTD existen dos tipos de atributos especiales (predefinidos), llamados: xml:lang y xml:space.

Uso del atributo xml:lang

En una DTD, el atributo xml:lang permite indicar el idioma del contenido y de los valores de los atributos de un elemento declarado. De forma que, cuando se utiliza xml:lang en un elemento, el idioma especificado afecta a todos los valores de sus posibles atributos y a todo su contenido, incluyendo a sus posibles sucesores a menos que se indique lo contrario con otra instancia de xml:lang.

EJEMPLO En la DTD del siguiente documento XML, con el atributo xml:lang se ha indicado el idioma de los elementos sigla y traduccion:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE siglas [
   <!ELEMENT siglas (sigla)*>
   <!ELEMENT sigla (significado, traduccion)>
      <!ATTLIST sigla letras CDATA #REQUIRED>
      <!ATTLIST sigla xml:lang CDATA "en">
   <!ELEMENT significado (#PCDATA)>
   <!ELEMENT traduccion (#PCDATA)>
      <!ATTLIST traduccion xml:lang CDATA #FIXED "es">
]>
<siglas>
   <sigla letras="ANSI">
      <significado>American National Standards Institute</significado>
      <traduccion>Instituto Nacional Estadounidense de Estándares</traduccion>
   </sigla>
   <sigla letras="ISO">
      <significado>International Organization for Standardization</significado>
      <traduccion>Organización Internacional de Normalización</traduccion>
   </sigla>
   <sigla letras="CERN" xml:lang="fr">
      <significado>Conseil Européen pour la Recherche Nucléaire</significado>
      <traduccion>Organización Europea para la Investigación Nuclear</traduccion>
   </sigla>
</siglas>
  • Inicialmente, para el elemento sigla se ha indicado el idioma inglés, en, por defecto.
  • No obstante, después se ha fijado el valor es, del español, para el atributo xml:lang del elemento traduccion.
  • Por otra parte, para el CERN se ha especificado que el idioma es el francés, fr.

Uso del atributo xml:space

En una DTD, el atributo xml:space permite indicar que los espacios en blanco, las tabulaciones y los retornos de carro que aparezcan en el contenido (texto) de un elemento -y sus sucesores a menos que se indique lo contrario con otra instancia de xml:space- tienen que ser preservados. Este atributo siempre tiene que ser declarado de tipo enumerado, siendo default, preserve o ambos, los posibles valores pertenecientes a la lista de valores que se indiquen entre paréntesis ().

EJEMPLO En la DTD del siguiente documento XML, con el atributo xml:space se ha indicado que, por defecto, los espacios que se escriban en el contenido de los elementos programa del documento, deben preservarse. Ahora bien, en la declaración de xml:space se ha indicado que su valor podría ser también default:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE programas [
  <!ELEMENT programas (programa)*>
  <!ELEMENT programa (#PCDATA)>
  <!ATTLIST programa xml:space (default|preserve) "preserve">
]>
<programas>
  <programa>/* Programa: Hola mundo */

#include &lt;conio.h&gt;
#include &lt;stdio.h&gt;

int main()
{
    printf( &quot;Hola mundo.&quot; );

    getch(); /* Pausa */

    return 0;
}</programa>
  <programa>/* Programa: Calificación según nota */

#include &lt;conio.h&gt;
#include &lt;stdio.h&gt;

int main()
{
    float nota;

    printf( &quot;\n   Introduzca nota (real): &quot; );
    scanf( &quot;%f&quot;, &amp;nota );

    if ( nota &gt;= 5 )
        printf( &quot;\n   APROBADO&quot; );
    else
        printf( &quot;\n   SUSPENDIDO&quot; );

    getch(); /* Pausa */

    return 0;
}</programa>
</programas>

En este ejemplo, los espacios en blanco, las tabulaciones y los retornos de carro de los dos programas escritos tienen que preservarse.

No obstante, tal y como está declarado el atributo xml:space del elemento programa, se podría asignar el valor default a xml:space en cualquier programa. En tal caso, sería el programa que procese el documento, el que decidiese qué tratamiento hacer a los espacios en blanco, las tabulaciones y los retornos de carro.

Declaración de entidades

En una DTD se pueden declarar entidades generales y paramétricas (de parámetro).

Las entidades generales pueden ser:

  • Entidades generales internas analizables
  • Entidades generales externas analizables
  • Entidades generales externas no analizables

Por otro lado, las entidades paramétricas pueden ser:

  • Entidades paramétricas internas analizables
  • Entidades paramétricas externas analizables

Las entidades generales pueden utilizarse en el cuerpo de un documento XML y en su DTD. Sin embargo, las entidades paramétricas solo pueden utilizarse dentro de la DTD.

¿Qué diferencia hay entre una entidad general y una entidad paramétrica?

¿Qué diferencia hay entre una entidad externa y una entidad interna?

Las entidades externas son entidades cuyo valor está en un fichero diferente del propio XML.

Las entidades internas son entidades cuyo valor está en el propio fichero XML.

¿Qué diferencia hay entre una entidad analizable y una entidad NO analizable?

Analizable significa que puede ser internamente por el analizador de XML. Por ejemplo en el caso de una imagen en formato PNG, el contenido de la imagen no lo podemos analizar con un DTD, es decir, no podemos saber nada de cómo es la imagen desde el documento XML.

Entidades generales internas analizables

Para declarar una entidad general interna analizable (parsed) en una DTD, se utiliza la siguiente sintaxis:

1
<!ENTITY nombre-de-la-entidad "valor-de-la-entidad">

EJEMPLO En la DTD del siguiente documento XML, se han declarado tres entidades (escritor, obra y fecha):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE textos [
   <!ELEMENT textos (texto)+>
   <!ELEMENT texto (#PCDATA)>
  
   <!ENTITY escritor "Miguel de Cervantes">
   <!ENTITY obra "El Quijote">
   <!ENTITY fecha "29/09/1947">
]>

<textos>
   <texto>&obra; fue escrito por &escritor;.</texto>
   <texto>&escritor; nació el &fecha;.</texto>
</textos>

Obsérvese que, para referenciar a las entidades, se ha utilizado la sintaxis:

1
&nombre-de-la-entidad;

Si este documento XML se visualizase en un navegador web, se vería algo parecido a:

imgDescription Visualización del archivo textos.xml en Google Chrome

Entidades generales externas analizables

En una DTD se pueden declarar dos tipos de entidades generales externas analizables (parsed): privadas y públicas. Para las privadas se utiliza SYSTEM, y para las públicas PUBLIC. La sintaxis en cada caso es:

1
<!ENTITY nombre-de-la-entidad SYSTEM "URI">
1
<!ENTITY nombre-de-la-entidad PUBLIC "identificador-público" "URI">

Entidades generales externas analizables privadas - SYSTEM

EJEMPLO En la DTD del siguiente documento XML, se ha declarado la entidad escritor:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE textos [
   <!ELEMENT textos (texto)+>
   <!ELEMENT texto (#PCDATA)>
  
   <!ENTITY escritor SYSTEM "escritor.txt">
]>

<textos>
   <texto>El Quijote fue escrito por &escritor;.</texto>
</textos>

Suponiendo que el archivo escritor.txt contenga:

1
Miguel de Cervantes

En un navegador web (por ejemplo en Internet Explorer 8) se podrá ver:

Visualización del archivo textos.xml en Internet Explorer 8 Visualización del archivo textos.xml en Internet Explorer 8

Entidades generales externas analizables públicas - PUBLIC

EJEMPLO Para declarar escritor como entidad general externa analizable pública, se puede escribir:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE textos [
   <!ELEMENT textos (texto)+>
   <!ELEMENT texto (#PCDATA)>
  
   <!ENTITY escritor PUBLIC "-//W3C//TEXT escritor//EN" "http://www.abrirllave.com/dtd/escritor.txt">
]>

<textos>
   <texto>El Quijote fue escrito por &escritor;.</texto>
</textos>
¿Qué diferencia hay entre una entidad pública (PUBLIC) y una entidad privada (SYSTEM)?

Ambas deben ser entidades generales externas analizables, pero la entidad privada hace referencia a un recurso privado mientras que la entidad pública hace referencia a un recurso público accesible a través de Internet.

Entidades generales externas no analizables

En una DTD, al igual que ocurre con las entidades generales externas analizables, se pueden declarar dos tipos de entidades generales externas no analizables (unparsed): privadas y públicas. Para las privadas se utiliza SYSTEM, y para las públicas PUBLIC. La sintaxis en cada caso es:

1
<!ENTITY nombre-de-la-entidad SYSTEM "URI" NDATA notación>
1
<!ENTITY nombre-de-la-entidad PUBLIC "identificador-público" "URI" NDATA notación>

Las entidades no analizables pueden contener cualquier tipo de datos (no XML). Por tanto, pueden hacer referencia a datos que un procesador XML no tiene porqué analizar, como por ejemplo una imagen.

Entidades generales externas no analizables privadas - SYSTEM

EJEMPLO En la DTD del siguiente documento XML, se indica que el elemento imagen que se escriba, tiene que incluir obligatoriamente el atributo fuente, cuyo valor será una entidad:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE imagen [
   <!ELEMENT imagen EMPTY>
      <!ATTLIST imagen fuente ENTITY #REQUIRED> 

   <!ENTITY logo SYSTEM "logo.gif" NDATA gif>

   <!NOTATION gif SYSTEM "image/gif">
]>

<imagen fuente="logo"/>
  • En la DTD de este ejemplo se está indicando que el valor -datos- de la entidad logo va a ser cargado desde una URI. En este caso, se hace referencia al archivo logo.gif.
  • Con NDATA (Notation Data) se indica que la entidad no es analizable y, en este caso, se ha asociado a la entidad logo con la notación gif.
  • La notación gif es una declaración del tipo MIME image/gif.

¿Por qué una entidad puede NO ser analizable?

Entidades generales externas no analizables públicas - PUBLIC

EJEMPLO Para declarar logo como entidad pública, se puede escribir:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE imagen [
   <!ELEMENT imagen EMPTY>
      <!ATTLIST imagen fuente ENTITY #REQUIRED> 

   <!ENTITY logo PUBLIC "-//W3C//GIF logo//EN" "http://www.abrirllave.com/dtd/logo.gif" NDATA gif>

   <!NOTATION gif SYSTEM "image/gif">
]>

<imagen fuente="logo"/>

Véase que, se referencia al archivo http://www.abrirllave.com/dtd/logo.gif.

Entidades paramétricas internas analizables

Para declarar una entidad paramétrica (de parámetro) interna analizable (parsed) en una DTD, se utiliza la siguiente sintaxis:

1
<!ENTITY % nombre-de-la-entidad "valor-de-la-entidad">

EJEMPLO La DTD del siguiente documento XML es externa, habiéndose escrito esta en el archivo persona.dtd:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE persona SYSTEM "persona.dtd">

<persona>
   <nombre>Iker</nombre>
   <mayor_de_edad/>
   <ciudad>Pamplona</ciudad>
</persona>

El contenido del archivo persona.dtd podría ser:

1
2
3
4
5
6
<!ENTITY % p "(#PCDATA)">

<!ELEMENT persona (nombre, mayor_de_edad?, ciudad)>
<!ELEMENT nombre %p;>
<!ELEMENT mayor_de_edad EMPTY>
<!ELEMENT ciudad %p;>

Obsérvese que, en la DTD se ha declarado la entidad paramétrica p y, para referenciarla, se utiliza la sintaxis:

1
%nombre-de-la-entidad;

Si este documento XML se visualizase en un navegador web, se vería algo similar a:

Visualización del archivo persona.xml en Google Chrome Visualización del archivo persona.xml en Google Chrome

Las entidades de parámetro se declaran antes de referenciarlas

En una DTD las entidades paramétricas tienen que declararse antes de ser referenciadas. Por tanto, no sería correcto haber escrito, por ejemplo:

1
2
3
4
5
6
<!ELEMENT persona (nombre, mayor_de_edad?, ciudad)>
<!ELEMENT nombre %p;>
<!ELEMENT mayor_de_edad EMPTY>
<!ELEMENT ciudad %p;>

<!ENTITY % p "(#PCDATA)">

A una entidad paramétrica interna no se le puede referenciar en una DTD interna

Las entidades paramétricas internas pueden declararse en DTD internas o externas. Sin embargo, no pueden referenciarse desde una DTD interna. En consecuencia, el siguiente documento no sería válido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE persona [
   <!ENTITY % p "(#PCDATA)">

   <!ELEMENT persona (nombre, mayor_de_edad?, ciudad)>
   <!ELEMENT nombre %p;>
   <!ELEMENT mayor_de_edad EMPTY>
   <!ELEMENT ciudad %p;>
]>

<persona>
   <nombre>Iker</nombre>
   <mayor_de_edad/>
   <ciudad>Pamplona</ciudad>
</persona>

Declaración de una entidad paramétrica en la DTD interna de un documento XML y referenciada en la DTD externa

Ahora bien, sí sería válido el siguiente documento XML, donde internamente se declara la entidad paramétrica p:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE persona SYSTEM "persona.dtd" [
   <!ENTITY % p "(#PCDATA)">
]>

<persona>
   <nombre>Iker</nombre>
   <mayor_de_edad/>
   <ciudad>Pamplona</ciudad>
</persona>

En este caso, el contenido del archivo persona.dtd podría ser:

1
2
3
4
<!ELEMENT persona (nombre, mayor_de_edad?, ciudad)>
<!ELEMENT nombre %p;>
<!ELEMENT mayor_de_edad EMPTY>
<!ELEMENT ciudad %p;>

Entidades paramétricas externas analizables

En una DTD se pueden declarar dos tipos de entidades paramétricas externas analizables (parsed): privadas y públicas. Para las privadas se utiliza SYSTEM, y para las públicas PUBLIC. La sintaxis en cada caso es:

1
2
<!ENTITY % nombre-de-la-entidad SYSTEM "URI">
%nombre-de-la-entidad;
1
2
<!ENTITY % nombre-de-la-entidad PUBLIC "identificador-público" "URI">
%nombre-de-la-entidad;

Entidades paramétricas externas analizables privadas - SYSTEM

EJEMPLO En la DTD del siguiente documento XML, se ha declarado la entidad persona:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE persona [
   <!ENTITY % persona SYSTEM "persona.dtd">
   %persona;
]>

<persona>
   <nombre>Iker</nombre>
   <mayor_de_edad/>
   <ciudad>Pamplona</ciudad>
</persona>

Suponiendo que el archivo persona.dtd contenga:

1
2
3
4
<!ELEMENT persona (nombre, mayor_de_edad?, ciudad)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT mayor_de_edad EMPTY>
<!ELEMENT ciudad (#PCDATA)>

En un navegador web (por ejemplo en Mozilla Firefox) se podrá ver:

Visualización del archivo persona.xml en Mozilla Firefox Visualización del archivo persona.xml en Mozilla Firefox

Entidades paramétricas externas analizables públicas - PUBLIC

EJEMPLO Para declarar persona como entidad paramétrica externa analizable pública, se puede escribir:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE persona [
   <!ENTITY % persona PUBLIC "-//W3C//TEXT persona//EN" "http://www.abrirllave.com/dtd/persona.dtd">
   %persona;
]>

<persona>
   <nombre>Iker</nombre>
   <mayor_de_edad/>
   <ciudad>Pamplona</ciudad>
</persona>

Uso de una entidad dentro de otra

EJEMPLO En la DTD del siguiente documento XML, se han declarado dos entidades generales internas analizables (color y frase):

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE frase [
   <!ELEMENT frase (#PCDATA)>

   <!ENTITY color "azul">
   <!ENTITY frase "El cielo es &color;.">
]>

<frase>&frase;</frase>

Obsérvese que, la entidad color ha sido referenciada en el valor de la entidad frase. De forma que, si este documento XML se visualizase en un navegador web, se vería:

Visualización del archivo frase.xml en Google Chrome Visualización del archivo frase.xml en Google Chrome

Referencia circular o recursiva de entidades

EJEMPLO La DTD del siguiente documento XML no es correcta, ya que, la entidad frase1 ha sido referenciada en el valor de la entidad frase2, y al revés también:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE frase [
   <!ELEMENT frase (#PCDATA)>

   <!ENTITY frase1 "Esta frase incluye a la &frase2;.">
   <!ENTITY frase2 "Esta frase incluye a la &frase1;.">
]>

<frase>&frase1;</frase>

Para que dicha DTD fuese correcta, habría que quitar una de las dos referencias a entidades. Por ejemplo escribiendo:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE frase [
   <!ELEMENT frase (#PCDATA)>

   <!ENTITY frase1 "Esta frase incluye a la &frase2;.">
   <!ENTITY frase2 "segunda frase">
]>

<frase>&frase1;</frase>

Declaración de notaciones

En una DTD se pueden declarar dos tipos de notaciones: privadas y públicas. Para las privadas se utiliza SYSTEM, y para las públicas PUBLIC, pudiéndose utilizar las siguientes sintaxis:

1
<!NOTATION nombre-de-la-notación SYSTEM "identificador-del-sistema">
1
<!NOTATION nombre-de-la-notación PUBLIC "identificador-público">
1
<!NOTATION nombre-de-la-notación PUBLIC "identificador-público" "identificador-del-sistema">

Notaciones para indicar el formato de entidades externas - Uso de SYSTEM

En la DTD de un documento XML, las notaciones se pueden utilizar para especificar el formato de entidades externas (datos no XML), como por ejemplo un archivo que contenga una imagen. Dichas entidades externas no las analizará un procesador XML, sino que serán tratadas por el programa que procese el documento.

EJEMPLO En la DTD del siguiente documento XML, se indica que los elementos fruta que se escriban, tienen que incluir obligatoriamente el atributo foto, cuyo valor será una entidad y, para indicar el formato de dicha entidad, se usa la notación gif:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE frutas [
   <!ELEMENT frutas (fruta)*>
   <!ELEMENT fruta EMPTY>
   <!ATTLIST fruta foto ENTITY #REQUIRED>

   <!ENTITY manzana SYSTEM "manzana.gif" NDATA gif>
   <!ENTITY naranja SYSTEM "naranja.gif" NDATA gif>

   <!NOTATION gif SYSTEM "image/gif">
]>

<frutas>
   <fruta foto="manzana"/>
   <fruta foto="naranja"/>
</frutas>
  • En la DTD de este ejemplo se está indicando que los valores -datos- de las entidades (manzana y naranaja) van a ser cargados desde una URI (Uniform Resource Identifier, Identificador Uniforme de Recurso). En este caso, se hace referencia a los archivos externos manzana.gif y naranja.gif.
  • Con NDATA (Notation Data) se ha asociado a las entidades manzana y naranaja con la notación gif.
  • La notación gif es una declaración del tipo MIME image/gif.

EJEMPLO Si en el sistema existe, por ejemplo, un programa llamado procesadorGIF.exe en la carpeta aplicaciones capaz de procesar imágenes GIF (Graphics Interchange Format, Formato de Intercambio de Gráficos), también se podría escribir:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE frutas [
   <!ELEMENT frutas (fruta)*>
   <!ELEMENT fruta EMPTY>
   <!ATTLIST fruta foto ENTITY #REQUIRED>

   <!ENTITY manzana SYSTEM "manzana.gif" NDATA gif>
   <!ENTITY naranja SYSTEM "naranja.gif" NDATA gif>

   <!NOTATION gif SYSTEM "aplicaciones/procesadorGIF.exe">
]>

<frutas>
   <fruta foto="manzana"/>
   <fruta foto="naranja"/>
</frutas>

Notación pública - PUBLIC

EJEMPLO En la declaración de una notación se puede indicar un identificador público estándar, como por ejemplo, GIF 1.0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE frutas [
   <!ELEMENT frutas (fruta)*>
   <!ELEMENT fruta EMPTY>
   <!ATTLIST fruta foto ENTITY #REQUIRED>

   <!ENTITY manzana SYSTEM "manzana.gif" NDATA gif>
   <!ENTITY naranja SYSTEM "naranja.gif" NDATA gif>

   <!NOTATION gif PUBLIC "GIF 1.0">
]>

<frutas>
   <fruta foto="manzana"/>
   <fruta foto="naranja"/>
</frutas>

EJEMPLO En la notación escrita en la DTD del siguiente documento XML, se ha declarado el tipo MIME imagen/gif e indicado el identificador público estándar GIF 1.0:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE frutas [
   <!ELEMENT frutas (fruta)*>
   <!ELEMENT fruta EMPTY>
   <!ATTLIST fruta foto ENTITY #REQUIRED>

   <!ENTITY manzana SYSTEM "manzana.gif" NDATA gif>
   <!ENTITY naranja SYSTEM "naranja.gif" NDATA gif>

   <!NOTATION gif PUBLIC "GIF 1.0" "image/gif">
]>

<frutas>
   <fruta foto="manzana"/>
   <fruta foto="naranja"/>
</frutas>

Atributos cuyo valor es el nombre de una notación

En una DTD, pueden existir elementos con atributos cuyo valor sea el nombre de una notación.

EJEMPLO En la DTD del siguiente documento XML, se indica que los elementos documento que se escriban, tienen que incluir obligatoriamente el atributo version, cuyo valor será una notación (h4 o h5):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE documentos [
   <!ELEMENT documentos (documento)*>
   <!ELEMENT documento (#PCDATA)>
   <!ATTLIST documento version NOTATION (h4|h5) #REQUIRED>

   <!NOTATION h5 PUBLIC "HTML 5">
   <!NOTATION h4 PUBLIC "HTML 4.01">
]>

<documentos>
   <documento version="h4"><!-- Código del documento 1. --></documento>
   <documento version="h5"><!-- Código del documento 2. --></documento>
   <documento version="h5"><!-- Código del documento 3. --></documento>
   <documento version="h4"><!-- Código del documento 4. --></documento>
</documentos>

HTML 5 y HTML 4.01 son identificadores públicos.

Secciones condicionales

En DTD externas se pueden definir las secciones IGNORE e INCLUDE, para ignorar o incluir declaraciones. Las sintaxis empleadas para ello son:

1
<![ IGNORE [ declaraciones ]]>
1
<![ INCLUDE [ declaraciones ]]>

El uso de las secciones condicionales suele estar ligado a entidades paramétricas.

EJEMPLO Si en un archivo llamado persona.dtd se ha escrito:

1
2
3
4
5
6
7
8
9
10
11
12
<![ %datos_basicos; [
   <!ELEMENT persona (nombre, edad)>
]]>

<![ %datos_ampliados; [
   <!ELEMENT persona (nombre, apellidos, edad, ciudad)>
]]>

<!ELEMENT nombre (#PCDATA)>
<!ELEMENT apellidos (#PCDATA)>
<!ELEMENT edad (#PCDATA)>
<!ELEMENT ciudad (#PCDATA)>

El siguiente documento XML sería válido:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE persona SYSTEM "persona.dtd" [
   <!ENTITY % datos_basicos "INCLUDE">
   <!ENTITY % datos_ampliados "IGNORE">
]>

<persona>
   <nombre>Elsa</nombre>
   <edad>23</edad>
</persona>

También sería válido el documento:

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE persona SYSTEM "persona.dtd" [
   <!ENTITY % datos_basicos "IGNORE">
   <!ENTITY % datos_ampliados "INCLUDE">
]>

<persona>
   <nombre>Ana</nombre>
   <apellidos>Sanz Tin</apellidos>
   <edad>19</edad>
   <ciudad>Pamplona</ciudad>
</persona>

Obsérvese que, en este ejemplo, en los dos documentos XML asociados a la DTD externa escrita en el archivo persona.dtd, se ha indicado -por medio de IGNORE e INCLUDE- si el elemento persona tiene que contener 2 ó 4 hijos, es decir, (nombre y edad) o (nombre, apellidos, edad y ciudad).

Espacios de nombres

EJEMPLO Dado el siguiente documento XML (visto en el apartado espacios de nombres del tutorial de XML) bien formado, pero no validado, donde se utilizan dos espacios de nombres (XML Namespaces):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<e1:ejemplo xmlns:e1="http://www.abrirllave.com/ejemplo1">
  
   <e1:carta>
      <e1:palo>Corazones</e1:palo>
      <e1:numero>7</e1:numero>
   </e1:carta>
  
   <e2:carta xmlns:e2="http://www.abrirllave.com/ejemplo2">
      <e2:carnes>
         <e2:filete_de_ternera precio="12.95"/>
         <e2:solomillo_a_la_pimienta precio="13.60"/>
      </e2:carnes>
      <e2:pescados>
         <e2:lenguado_al_horno precio="16.20"/>
         <e2:merluza_en_salsa_verde precio="15.85"/>
      </e2:pescados>
   </e2:carta>
  
</e1:ejemplo>

Se podría escribir dicho documento XML con una DTD interna como se muestra a continuación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE e1:ejemplo [
   <!ELEMENT e1:ejemplo (e1:carta, e2:carta)>
      <!ATTLIST e1:ejemplo xmlns:e1 CDATA #FIXED "http://www.abrirllave.com/ejemplo1">
   <!ELEMENT e1:carta (e1:palo, e1:numero)>
   <!ELEMENT e1:palo (#PCDATA)>
   <!ELEMENT e1:numero (#PCDATA)>

   <!ELEMENT e2:carta (e2:carnes, e2:pescados)>
      <!ATTLIST e2:carta xmlns:e2 CDATA #FIXED "http://www.abrirllave.com/ejemplo2">
   <!ELEMENT e2:carnes (e2:filete_de_ternera, e2:solomillo_a_la_pimienta)>
   <!ELEMENT e2:pescados (e2:lenguado_al_horno, e2:merluza_en_salsa_verde)>
   <!ELEMENT e2:filete_de_ternera EMPTY>
      <!ATTLIST e2:filete_de_ternera precio CDATA #REQUIRED>
   <!ELEMENT e2:solomillo_a_la_pimienta EMPTY>
      <!ATTLIST e2:solomillo_a_la_pimienta precio CDATA #REQUIRED>
   <!ELEMENT e2:lenguado_al_horno EMPTY>
      <!ATTLIST e2:lenguado_al_horno precio CDATA #REQUIRED>
   <!ELEMENT e2:merluza_en_salsa_verde EMPTY>
      <!ATTLIST e2:merluza_en_salsa_verde precio CDATA #REQUIRED>
]>

<e1:ejemplo xmlns:e1="http://www.abrirllave.com/ejemplo1">
  
   <e1:carta>
      <e1:palo>Corazones</e1:palo>
      <e1:numero>7</e1:numero>
   </e1:carta>
  
   <e2:carta xmlns:e2="http://www.abrirllave.com/ejemplo2">
      <e2:carnes>
         <e2:filete_de_ternera precio="12.95"/>
         <e2:solomillo_a_la_pimienta precio="13.60"/>
      </e2:carnes>
      <e2:pescados>
         <e2:lenguado_al_horno precio="16.20"/>
         <e2:merluza_en_salsa_verde precio="15.85"/>
      </e2:pescados>
   </e2:carta>
  
</e1:ejemplo>

Comentarios

En una DTD asociada a un documento XML, se pueden escribir comentarios entre los caracteres <!-- y -->. Por ejemplo:

1
<!-- Esto es un comentario escrito en una DTD -->

EJEMPLO En la DTD interna del siguiente documento se han escrito dos comentarios:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- Ejemplo de documento XML con comentarios en su DTD interna, del Tutorial de DTD de Abrirllave.com -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ciudades [
   <!ELEMENT ciudades (ciudad*)>
   <!ELEMENT ciudad (#PCDATA)>
      <!-- pais es atributo del elemento ciudad -->
      <!ATTLIST ciudad pais CDATA #REQUIRED>
]>

<ciudades>
   <ciudad pais="Italia">Roma</ciudad>
   <ciudad pais="Francia">París</ciudad>
   <ciudad pais="Alemania">Berlín</ciudad>
   <ciudad pais="">Viena</ciudad>
</ciudades>

Bibliografía

Este artículo está licenciado bajo CC BY 4.0 por el autor.

Aprendizaje No Supervisado

XSD (XML Schema Definition)