XML y sus gramáticas
Qué es XML y en qué se diferencia de SGML y de HTML, cómo se escribe un documento, la distinción entre estar bien formado y ser válido, los espacios de nombres y las dos formas de declarar la gramática: DTD y XSD.
Qué es XML y de dónde viene
XML es un estándar del W3C que deriva de SGML. No sirve para presentar información, sino para estructurarla: se usa para ficheros de configuración, para intercambiar datos entre sistemas distintos y para estandarizar el formato de esa información, que es lo que hace posible la interoperabilidad entre aplicaciones que no se conocen entre sí.
SGML era enorme y muy permisivo. XML es un subconjunto que le añade restricciones para simplificarlo, y son justo esas restricciones las que se preguntan, porque marcan la diferencia con el HTML al que estamos acostumbrados.
- Todas las etiquetas llevan cierre, incluidas las que no tienen contenido: o se cierran aparte o se autocierran con una barra.
- Los valores de los atributos van siempre entre comillas, simples o dobles. En HTML podían ir sueltos.
- XML distingue mayúsculas de minúsculas: <Tema> y <tema> son etiquetas distintas.
| Lenguaje | Relación con SGML y XML |
|---|---|
| HTML 4.01 | Era una aplicación de SGML y estaba alineado con él |
| HTML5 | Ya no es SGML: se define por sí mismo |
| XHTML | Es HTML reescrito con las reglas estrictas de XML. Su tipo MIME es application/xhtml+xml |
En XML no hay etiquetas predefinidas: el vocabulario lo inventa quien escribe el documento. Lo que XML fija son las reglas de escritura, no las palabras.
Para el examen
Etiquetas predefinidas: ninguna: el vocabulario lo inventa quien escribe el documento
Qué fija XML: las reglas de escritura, no las palabras
La declaración XML y el atributo standalone
Un documento XML puede empezar por una declaración, que siempre arranca con <?xml. La declaración es opcional, pero si se pone, el número de versión es obligatorio; el juego de caracteres y el atributo standalone, en cambio, se pueden omitir.
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE temario SYSTEM "temario.dtd">
<temario bloque="3">
<tema id="7" nivel="1">
<titulo>Aplicaciones web</titulo>
<subtemas>8</subtemas>
</tema>
</temario>standalone es el que más se pregunta porque su nombre engaña. No dice si el documento se vale por sí mismo en un sentido vago: dice si necesita o no una gramática externa. Con standalone="no" el documento declara que su DTD está en un fichero aparte; con standalone="yes" declara que la gramática viaja dentro del propio fichero XML y no hace falta ir a buscar nada fuera. El valor por defecto, si no se escribe, es "no".
La gramática externa se enlaza con una declaración DOCTYPE que nombra el elemento raíz y la ruta del fichero. La palabra SYSTEM se usa cuando esa ruta es local o privada; PUBLIC, cuando se trata de una gramática publicada e identificada por un nombre normalizado.
Para el examen
La declaración: es opcional, pero si se pone, la versión es obligatoria
standalone: dice si el documento necesita una gramática EXTERNA; por defecto vale no
En el DOCTYPE: SYSTEM es ruta local y PUBLIC gramática normalizada
Entidades, secciones CDATA y elementos vacíos
Dentro de un documento XML hay caracteres que no se pueden escribir tal cual porque el analizador los interpretaría como marcado. El menor que abriría una etiqueta y el ampersand abriría una referencia. Para escribirlos como texto se usan las entidades, que funcionan como una macro o un escape: el analizador las sustituye por el carácter real al leer el documento.
| Entidad | Carácter que representa |
|---|---|
| & | El ampersand: & |
| < | El signo menor que |
| > | El signo mayor que |
| " | La comilla doble |
| ' | La comilla simple |
Cuando el texto a escapar es largo, escribir entidad por entidad es inviable. Para eso está la sección CDATA: todo lo que va dentro se lo salta el analizador y se devuelve literalmente, sin interpretarlo. Es lo que se usa para meter dentro de un XML un fragmento de código, una expresión regular o un trozo de HTML.
<pregunta id="q4">
<enunciado>¿Qué selecciona nav > a frente a nav a?</enunciado>
<ayuda>
<![CDATA[
La regla de CSS es: nav > a { font-weight: 600; }
El analizador no interpreta nada de lo que hay aquí dentro.
]]>
</ayuda>
<!-- Elemento vacío: sin hijos, pero con atributos -->
<revisada por="tutor" fecha="2026-08-16" />
</pregunta>Un elemento vacío es el que no tiene contenido. En XML puede escribirse de dos formas equivalentes: abriendo y cerrando seguido, o autocerrando con la barra antes del mayor que. No puede tener elementos hijos, pero sí puede llevar atributos, que es exactamente lo que hace útil el ejemplo anterior.
Para el examen
Entidades: escapan los caracteres que el analizador interpretaría como marcado
Sección CDATA: se salta el análisis de un bloque entero
Elemento vacío: no tiene hijos, pero sí puede llevar atributos
Espacios de nombres
Como el vocabulario de XML lo inventa cada uno, es cuestión de tiempo que dos vocabularios distintos usen la misma palabra para cosas distintas. Si en un mismo documento se mezclan el vocabulario del temario y el de la facturación, y los dos tienen un elemento llamado <titulo>, el analizador no puede saber cuál es cuál.
Los espacios de nombres resuelven ese choque permitiendo poner un prefijo en las etiquetas. El prefijo se declara con el atributo xmlns seguido de dos puntos y el nombre elegido, y se le asocia un URI que actúa como identificador único del vocabulario. Ese URI no tiene por qué apuntar a ninguna página real: es una etiqueta, no una dirección que se vaya a visitar.
<matricula xmlns:t="https://llegandoalcorte.com/ns/temario"
xmlns:f="https://llegandoalcorte.com/ns/facturacion">
<t:curso>
<t:titulo>Curso Largo TAI 2026</t:titulo>
</t:curso>
<f:recibo>
<f:titulo>Recibo 2026/0431</f:titulo>
<f:importe>590.00</f:importe>
</f:recibo>
</matricula>Los espacios de nombres quedan fuera del alcance de un DTD, que es anterior a ellos. Los esquemas XSD sí, y esa es una de las razones por las que los desplazaron.
Para el examen
DTD: no los entiende: es anterior a ellos
XSD: sí los entiende
Consecuencia: es una de las razones por las que XSD desplazó al DTD
Documento bien formado y documento válido
Es la distinción central de todo XML y cae en examen con mucha frecuencia. Son dos niveles distintos de exigencia, y el segundo incluye al primero.
Un documento está BIEN FORMADO si cumple las reglas de sintaxis de XML. Es una comprobación puramente gramatical: no hace falta ninguna gramática externa, cualquier analizador puede hacerla solo leyendo el fichero.
- Existe un único elemento raíz que engloba a todos los demás.
- Todos los elementos están correctamente anidados y correctamente cerrados: no se pueden cruzar las etiquetas.
- Los valores de los atributos van entre comillas simples o dobles.
- Los elementos vacíos terminan en autocierre o llevan su etiqueta de fin.
- Los nombres de etiqueta son alfanuméricos y empiezan por letra, guion bajo o dos puntos.
Un documento es VÁLIDO si, además de estar bien formado, cumple las reglas de una gramática concreta declarada en un DTD o en un XSD: que los elementos sean los previstos, que estén en el orden previsto, que las cardinalidades cuadren y que los atributos obligatorios estén presentes.
| Bien formado | Válido | |
|---|---|---|
| Qué comprueba | La sintaxis de XML | La sintaxis y además la gramática declarada |
| Necesita DTD o XSD | No | Sí |
| Ejemplo de fallo | Una etiqueta sin cerrar | Un <tema> sin el <titulo> que el esquema exige |
Todo documento válido está bien formado, pero no todo documento bien formado es válido. La implicación va en un solo sentido y es la pregunta clásica.
Para el examen
Bien formado: cumple las reglas de sintaxis de XML
Válido: además se ajusta a una gramática
Sentido de la implicación: todo válido está bien formado, pero no al revés
DTD: la primera gramática de XML
DTD son las siglas de Document Type Definition. Fue la primera forma de describir la estructura de un documento XML y viene heredada de SGML. Puede vivir en un fichero aparte y enlazarse con DOCTYPE, o escribirse dentro del propio documento entre corchetes, que es el caso de standalone="yes".
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!DOCTYPE temario [
<!ELEMENT temario (tema)+>
<!ELEMENT tema (titulo, resumen?, subtema*)>
<!ELEMENT titulo (#PCDATA)>
<!ELEMENT resumen (#PCDATA)>
<!ELEMENT subtema (#PCDATA)>
<!ATTLIST tema id ID #REQUIRED>
<!ATTLIST tema nivel CDATA #IMPLIED>
<!ATTLIST tema bloque CDATA #FIXED "3">
]>
<temario>
<tema id="t7" nivel="1">
<titulo>Aplicaciones web</titulo>
<subtema>XML bien formado y válido</subtema>
</tema>
</temario>La declaración <!ELEMENT> dice qué elementos existen y qué pueden contener. El contenido se expresa con tres tipos: #PCDATA indica que el elemento contiene texto analizable; ANY permite contenido mixto, es decir, texto o cualquier otro elemento dentro; y EMPTY declara un elemento vacío. La cardinalidad se marca con tres símbolos detrás del nombre.
| Símbolo | Cuántas veces puede aparecer |
|---|---|
| (sin símbolo) | Exactamente una vez |
| ? | Cero o una vez: opcional |
| * | Cero o muchas veces |
| + | Una o muchas veces: al menos una |
La declaración <!ATTLIST> describe los atributos de un elemento. Cada uno lleva su tipo y su obligatoriedad. El tipo CDATA es texto sin más; el tipo ID funciona como una clave primaria, ya que su valor tiene que ser único en el documento, e IDREF como una clave ajena que apunta a un ID existente. La obligatoriedad se declara con #REQUIRED si el atributo es obligatorio, #IMPLIED si es opcional y #FIXED si su valor está fijado de antemano.
El punto flaco de DTD, y la razón de que XSD lo sustituyera, es que no tiene tipos de datos: para un DTD todo es texto. No sabe distinguir una fecha de un número ni imponer un rango de valores.
Para el examen
Qué es: la primera gramática de XML
Su punto flaco: no tiene tipos de datos: para un DTD todo es texto
XSD: esquemas con tipos de datos y facetas
XSD son las siglas de XML Schema Definition. Es la gramática que sustituyó a los DTD y tiene dos ventajas decisivas: se escribe en el propio XML, así que se procesa con las mismas herramientas que los datos, y sobre todo maneja tipos de datos de verdad, con lo que se pueden imponer restricciones sobre los valores y no solo sobre la estructura.
| DTD | XSD | |
|---|---|---|
| Sintaxis | Propia, heredada de SGML | XML |
| Tipos de datos | No: todo es texto | Sí: cadenas, números, fechas, tipos propios |
| Restricciones sobre valores | No | Sí, mediante facetas |
| Espacios de nombres | No los soporta | Sí |
Para agrupar elementos hijos, XSD ofrece tres indicadores de orden. Con xs:sequence los hijos tienen que aparecer exactamente en el orden declarado; con xs:all pueden aparecer en cualquier orden; y con xs:choice tiene que aparecer uno cualquiera de los declarados, pero solo uno. La cardinalidad ya no se expresa con símbolos sino con los atributos minOccurs y maxOccurs, cuyo valor por defecto, si no se escriben, es uno; maxOccurs admite además el valor unbounded para «sin límite».
Las restricciones finas sobre el valor de un tipo se llaman facetas. Son el mecanismo que permite decir no solo «esto es un número», sino «esto es un número entre 1 y 33».
| Faceta | Qué restringe |
|---|---|
| xs:length, xs:minLength, xs:maxLength | La longitud exacta, mínima y máxima |
| xs:pattern | Un patrón de expresión regular que el valor debe cumplir |
| xs:enumeration | La lista cerrada de valores admitidos |
| xs:minInclusive y xs:maxInclusive | Los límites del rango, incluyéndolos |
| xs:minExclusive y xs:maxExclusive | Los límites del rango, sin incluirlos |
| xs:totalDigits y xs:fractionDigits | Cuántas cifras en total y cuántas decimales |
| xs:whiteSpace | Qué hacer con los espacios en blanco: conservarlos, reemplazarlos o colapsarlos |
<xs:element name="tema">
<xs:complexType>
<xs:sequence>
<xs:element name="titulo" type="xs:string"/>
<xs:element name="subtema" type="xs:string"
minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="id" type="xs:ID" use="required"/>
<xs:attribute name="nivel">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="3"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>En XSD, minOccurs y maxOccurs valen 1 cuando no se escriben. Poner minOccurs="0" es la forma de declarar un elemento opcional, equivalente al signo de interrogación de un DTD.
Para el examen
minOccurs y maxOccurs por defecto: 1 los dos
Elemento opcional: minOccurs a cero
Diferencia con el DTD: el propio esquema es un documento XML