Introducción a Document Type Definition (DTD) en XML

por

en

Cuando hablamos de XML (eXtensible Markup Language), nos referimos a un lenguaje ampliamente utilizado para el intercambio de datos en la web y más allá. Pero, ¿Cómo garantizamos que nuestros documentos XML estén bien estructurados y sigan las reglas que necesitamos? Aquí es donde entra en juego DTD (Document Type Definition), una herramienta esencial para la validación de documentos XML.

¿Qué es DTD?

DTD, o Definición de Tipo de Documento, es un conjunto de reglas que definen la estructura de un documento SGML (Standard Generalized Markup Language) o XML. En términos más simples, DTD actúa como un mapa que describe qué elementos y atributos son permitidos en un documento XML y cómo deben organizarse.

Relación con SGML y XML

SGML, o Lenguaje de Marcado Generalizado Estándar, es el ancestro de XML. XML, a su vez, es una simplificación de SGML desarrollada por el W3C (World Wide Web Consortium). DTD, aunque se originó en SGML, también se aplica a XML, permitiendo la validación de documentos XML de acuerdo con las reglas establecidas.

Validación XML

La validación de documentos XML es crucial para garantizar su integridad y consistencia. Un documento XML válido no solo está bien formado, sino que también cumple con las reglas definidas en su DTD. Esto asegura que el documento se ajuste a la estructura esperada y pueda ser procesado correctamente por aplicaciones y sistemas.

Alternativas a DTD

Si bien DTD es una herramienta poderosa, no es la única opción para validar documentos XML. Otros métodos como XML Schema o RELAX NG también ofrecen capacidades de validación avanzadas y una mayor expresividad en la definición de la estructura de un documento XML. La elección entre DTD y estas alternativas depende de los requisitos específicos del proyecto y las preferencias del desarrollador.

En conclusión, DTD desempeña un papel fundamental en la validación de documentos XML, proporcionando un marco para definir su estructura y asegurar su conformidad con las especificaciones establecidas. Comprender cómo utilizar DTD es esencial para cualquier desarrollador o profesional que trabaje con XML, ya que garantiza la calidad y la interoperabilidad de los datos intercambiados en entornos web y más allá.

Algunos ejemplos de DTD

DTD para un Libro

Supongamos que queremos definir la estructura de un documento XML que representa la información de un libro. Podemos utilizar DTD de la siguiente manera:

<!DOCTYPE libro [
  <!ELEMENT libro (titulo, autor, año)>
  <!ELEMENT titulo (#PCDATA)>
  <!ELEMENT autor (#PCDATA)>
  <!ELEMENT año (#PCDATA)>
]>

En este ejemplo, hemos definido que un elemento libro debe contener tres subelementos: titulo, autor y año, cada uno de los cuales contiene datos de texto (#PCDATA).

DTD para una Lista de Contactos

Ahora, supongamos que queremos definir la estructura de un documento XML que almacena información de contactos. Podemos utilizar DTD de la siguiente manera:

<!DOCTYPE contactos [
  <!ELEMENT contactos (contacto*)>
  <!ELEMENT contacto (nombre, telefono, email?)>
  <!ELEMENT nombre (#PCDATA)>
  <!ELEMENT telefono (#PCDATA)>
  <!ELEMENT email (#PCDATA)>
]>

En este ejemplo, hemos definido que un elemento contactos puede contener cero o más elementos contacto, cada uno de los cuales debe contener un nombre y un teléfono, y opcionalmente puede contener un email.

Sintaxis para escribir una DTD interna

Una DTD interna se incluye directamente en el documento XML utilizando la declaración <!DOCTYPE>. Esto significa que la definición de la estructura del documento y las reglas de validación están presentes dentro del propio archivo XML. Esto puede resultar útil para documentos XML pequeños o cuando no se desea mantener un archivo DTD separado.

La sintaxis para escribir una DTD interna sigue un conjunto de reglas simples que definen los elementos, atributos y entidades permitidos en el documento XML. Aquí hay un ejemplo básico de cómo se ve una DTD interna.

En este ejemplo, nombre_del_documento es el nombre del documento XML y las definiciones de elementos, atributos y entidades se encuentran entre corchetes.

<!DOCTYPE nombre_del_documento [
  <!-- Definiciones de elementos, atributos y entidades -->
]>

Elementos DTD, secuencia y cardinalidad

Para definir elementos en una DTD interna, se utiliza la declaración <!ELEMENT>.

<!ELEMENT elemento_nombre (contenido)>

Donde elemento_nombre es el nombre del elemento y contenido es lo que puede contener el elemento, como datos de texto (#PCDATA), otros elementos, o combinaciones de ellos.

<!DOCTYPE ciudad [
<!ELEMENT ciudad (nombre, pais)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT pais (#PCDATA)>
]>

Cuando trabajamos con los elementos DTD debemos tener en cuenta la secuencia. La secuencia se refiere al orden en el que aparecen los elementos dentro de un elemento principal en un documento XML.

En DTD, la secuencia se define mediante la colocación de elementos en el orden deseado dentro de la definición de un elemento.

<!ELEMENT ejemplo (elemento1, elemento2, elemento3)>

Otro aspecto a tener en cuenta es la cardinalidad. La cardinalidad se refiere a la cantidad de veces que un elemento puede aparecer dentro de un elemento principal en un documento XML. En DTD, la cardinalidad se especifica utilizando los cuantificadores '*', ‘+' y ‘?'

* (cero o más veces): Indica que el elemento puede aparecer cero o más veces dentro del elemento principal. Por ejemplo:

<!ELEMENT ejemplo (elemento*)>

+ (una o más veces): Indica que el elemento debe aparecer al menos una vez dentro del elemento principal. Por ejemplo:

<!ELEMENT ejemplo (elemento+)>

? (cero o una vez): Indica que el elemento puede aparecer cero o una vez dentro del elemento principal. Por ejemplo:

<!ELEMENT ejemplo (elemento?)>

Atributos DTD

Para definir atributos en una DTD interna, se utiliza la declaración <!ATTLIST>. Por ejemplo:

<!ATTLIST elemento_nombre atributo_tipo valor_por_defecto>

Donde elemento_nombre es el nombre del elemento al que pertenece el atributo, atributo_tipo es el tipo de datos del atributo (como CDATA, ID, etc.) y valor_por_defecto es el valor predeterminado del atributo.

Ejemplos completos de una DTD interna

En este primer ejemplo tenemos como elemento raíz lista_tareas, que puede contener cualquier número de elementos tarea. Cada tarea contiene datos de texto (#PCDATA), lo que significa que puede contener cualquier cadena de caracteres.

<!DOCTYPE lista_tareas [
  <!ELEMENT lista_tareas (tarea*)>
  <!ELEMENT tarea (#PCDATA)>
]>
<lista_tareas>
  <tarea>Completar informe</tarea>
  <tarea>Enviar correo electrónico</tarea>
</lista_tareas>

En el segundo ejemplo el elemento raíz se llama contactos, que puede contener cualquier número de elementos contacto. Cada contacto debe contener un nombre y un teléfono, y opcionalmente puede contener un email

<!DOCTYPE contactos [
  <!ELEMENT contactos (contacto*)>
  <!ELEMENT contacto (nombre, telefono, email?)>
  <!ELEMENT nombre (#PCDATA)>
  <!ELEMENT telefono (#PCDATA)>
  <!ELEMENT email (#PCDATA)>
]>
<contactos>
  <contacto>
    <nombre>Juan Perez</nombre>
    <telefono>123456789</telefono>
    <email>juan@example.com</email>
  </contacto>
  <contacto>
    <nombre>María García</nombre>
    <telefono>987654321</telefono>
  </contacto>
</contactos>

Como tercer ejemplo simple tenemos un elemento raíz estudiantes, que puede contener cualquier número de elementos estudiante. Cada estudiante debe contener un nombre, una edad y una carrera.

<!DOCTYPE estudiantes [
  <!ELEMENT estudiantes (estudiante*)>
  <!ELEMENT estudiante (nombre, edad, carrera)>
  <!ELEMENT nombre (#PCDATA)>
  <!ELEMENT edad (#PCDATA)>
  <!ELEMENT carrera (#PCDATA)>
]>
<estudiantes>
  <estudiante>
    <nombre>Carlos Sánchez</nombre>
    <edad>20</edad>
    <carrera>Ingeniería Informática</carrera>
  </estudiante>
  <estudiante>
    <nombre>Laura Gómez</nombre>
    <edad>22</edad>
    <carrera>Administración de Empresas</carrera>
  </estudiante>
</estudiantes>

Como ejemplo más complejo podríamos ver este:

Teniendo un elemento raíz estudiantes, que puede contener uno o más elementos estudiante. Cada estudiante debe contener un nombre, una lista de materias y opcionalmente notas. Cada materias contiene uno o más elementos materia. Cada materia debe contener un nombre y una nota. El elemento opcional notas permite que algunos estudiantes no tengan notas registradas.

<!DOCTYPE estudiantes [
  <!ELEMENT estudiantes (estudiante+)>
  <!ELEMENT estudiante (nombre, materias, notas?)>
  <!ELEMENT nombre (#PCDATA)>
  <!ELEMENT materias (materia+)>
  <!ELEMENT materia (nombre, nota)>
  <!ELEMENT notas (#PCDATA)>
]>
<estudiantes>
  <estudiante>
    <nombre>Juan Perez</nombre>
    <materias>
      <materia>
        <nombre>Matemáticas</nombre>
        <nota>8.5</nota>
      </materia>
      <materia>
        <nombre>Física</nombre>
        <nota>7.0</nota>
      </materia>
    </materias>
    <notas>Excelente</notas>
  </estudiante>
  <estudiante>
    <nombre>Maria González</nombre>
    <materias>
      <materia>
        <nombre>Lengua</nombre>
        <nota>9.0</nota>
      </materia>
      <materia>
        <nombre>Historia</nombre>
        <nota>6.5</nota>
      </materia>
      <materia>
        <nombre>Química</nombre>
        <nota>8.2</nota>
      </materia>
    </materias>
  </estudiante>
  <estudiante>
    <nombre>Carlos Pérez</nombre>
    <materias>
      <materia>
        <nombre>Geografía</nombre>
      </materia>
    </materias>
    <!-- Podemos ver como no hay notas en este estudiante -->
  </estudiante>
</estudiantes>