Lenguajes de Marcas en DAM, DAW y ASIR: XML, DTD, XSD, XPath y XSLT con ejercicios de examen resueltos

Lenguajes de Marcas y Sistemas de Gestión de Información (LMSGI) es el módulo de primero de DAM, DAW y ASIR en el que aprendes a estructurar, validar, consultar y transformar información con lenguajes de marcas: HTML y CSS para la web, XML para los datos, DTD y XML Schema (XSD) para validarlos, XPath y XQuery para consultarlos y XSLT para convertirlos en otra cosa, normalmente una página HTML. Para aprobarlo tienes que saber detectar por qué un XML no está bien formado, escribir una DTD y un XSD a partir de un documento, sacar los nodos que te piden con XPath y escribir una hoja XSLT que genere una tabla.
Tiene fama de ser el módulo más amable de primero, y para muchos lo es. El problema es que casi todos los ejercicios se hacen en papel y no perdonan un detalle: una mayúscula que no coincide hace que el XML no esté bien formado, un + en lugar de un * cambia lo que acepta la DTD y un predicado XPath mal colocado devuelve otros nodos. Aquí tienes qué entra, seis ejercicios de examen resueltos sobre el mismo documento, las preguntas de test que más se repiten, los errores que más vemos en clase y cómo prepararlo.
Qué entra en Lenguajes de Marcas
Es el módulo 0373 y es común a los tres ciclos: aparece con el mismo código en DAM, DAW y ASIR, y se da en primer curso. El peso de cada bloque cambia mucho según el centro: en algunos la mitad del curso es HTML y CSS, y en otros casi todo es XML.
| Bloque | Qué te piden | Lo que más falla |
|---|---|---|
| Características de los lenguajes de marcas | Qué es un lenguaje de marcas, HTML frente a XML, documento bien formado, entidades, espacios de nombres | Confundir bien formado con válido |
| Lenguajes de marcas en la web | HTML semántico, formularios, CSS (selectores, modelo de caja, Flexbox, responsive) | La especificidad de los selectores y el modelo de caja |
| Canales de contenidos | RSS y Atom: estructura de un feed y sus elementos obligatorios | Olvidar elementos obligatorios del channel |
| Validación | DTD y XML Schema (XSD): elementos, atributos, cardinalidad, tipos y restricciones | Cardinalidades (?, *, +) y el orden de los elementos |
| Conversión de documentos | XPath y XSLT: seleccionar nodos y transformar XML en HTML u otro XML | Rutas relativas dentro de for-each y predicados mal puestos |
| Almacenamiento | XQuery y bases de datos XML nativas (BaseX, eXist-db), JSON | La sintaxis FLWOR y ordenar números como si fueran texto |
| Sistemas de gestión empresarial | ERP y CRM, normalmente con Odoo: instalación, módulos e informes | Tratarlo como teoría pura y no haber tocado la herramienta |
Lo normal es que se evalúe con exámenes de ejercicios (a menudo en papel), prácticas entregables (una web con HTML y CSS, un XML con su DTD y su XSD, una transformación XSLT) y, en muchos centros a distancia, cuestionarios tipo test.
Bien formado y válido: la diferencia que siempre preguntan
Un documento XML está bien formado cuando cumple las reglas de sintaxis de XML: un único elemento raíz, todas las etiquetas cerradas y bien anidadas, mayúsculas y minúsculas coherentes, valores de atributos entre comillas y caracteres especiales escapados. Si no está bien formado, no es XML y ningún programa lo va a procesar.
Un documento es válido cuando, además de estar bien formado, cumple las reglas de una DTD o de un XSD: qué elementos puede haber, en qué orden, cuántas veces y con qué atributos y tipos de dato.
Todo documento válido está bien formado, pero no al revés. Un XML perfectamente escrito con los elementos en otro orden del que pide la DTD está bien formado y no es válido.
El documento de los ejercicios
Todos los ejercicios trabajan sobre el mismo fichero, biblioteca.xml. Hacerlo así es la mejor forma de estudiar: el mismo documento te sirve para escribir su DTD, su XSD, las consultas y la transformación.
<?xml version="1.0" encoding="UTF-8"?>
<biblioteca>
<libro id="L1" genero="novela">
<titulo>Cien años de soledad</titulo>
<autor>Gabriel García Márquez</autor>
<anio>1967</anio>
<precio>22.50</precio>
</libro>
<libro id="L2" genero="tecnico">
<titulo>Patrones de diseño</titulo>
<autor>Erich Gamma</autor>
<autor>Richard Helm</autor>
<autor>Ralph Johnson</autor>
<autor>John Vlissides</autor>
<anio>1994</anio>
<precio>45.00</precio>
<prestado/>
</libro>
<libro id="L3" genero="ensayo">
<titulo>Sapiens</titulo>
<autor>Yuval Noah Harari</autor>
<anio>2011</anio>
<precio>24.90</precio>
</libro>
<libro id="L4" genero="novela">
<titulo>La sombra del viento</titulo>
<autor>Carlos Ruiz Zafón</autor>
<anio>2001</anio>
<precio>19.90</precio>
<prestado/>
</libro>
</biblioteca>
Fíjate en tres detalles que se usan en los ejercicios: un libro puede tener varios autores, <prestado/> es un elemento vacío que solo aparece en los libros prestados, y id y genero son atributos, no elementos.
Seis ejercicios típicos resueltos
1. Encontrar los errores de un XML
Enunciado: indica por qué este documento no está bien formado y corrígelo.
<?xml version="1.0" encoding="UTF-8"?>
<biblioteca>
<libro id=L5 genero="novela">
<titulo>Rayuela</Titulo>
<autor>Julio Cortázar
<anio>1963</anio>
<precio>Menos de 20 € & envío gratis</precio>
</libro>
</biblioteca>
<libro id="L6" genero="ensayo">
<titulo>El infinito en un junco</titulo>
</libro>
Los errores, en el orden en que aparecen:
| Línea | Error | Regla que incumple |
|---|---|---|
id=L5 |
El valor del atributo no va entre comillas | Los valores de los atributos van siempre entre comillas dobles o simples |
<titulo>…</Titulo> |
La etiqueta de cierre no coincide | XML distingue mayúsculas de minúsculas: titulo y Titulo son dos nombres distintos |
<autor>Julio Cortázar |
La etiqueta no se cierra, y por eso anio y precio quedan dentro de autor |
Toda etiqueta abierta se cierra, y en orden inverso al de apertura |
€ & envío |
& sin escapar |
& y < no pueden aparecer sueltos en el texto: se escriben & y < |
El segundo <libro> |
Está fuera de <biblioteca>, así que el documento tiene dos raíces |
Un documento XML tiene un único elemento raíz |
Corregido:
<?xml version="1.0" encoding="UTF-8"?>
<biblioteca>
<libro id="L5" genero="novela">
<titulo>Rayuela</titulo>
<autor>Julio Cortázar</autor>
<anio>1963</anio>
<precio>Menos de 20 € & envío gratis</precio>
</libro>
<libro id="L6" genero="ensayo">
<titulo>El infinito en un junco</titulo>
</libro>
</biblioteca>
Lo que hay que entender: ahora está bien formado, pero con la DTD del ejercicio 2 seguiría sin ser válido, porque a L6 le faltan autor, anio y precio. Y con el XSD del ejercicio 3 fallaría también el precio de L5, que es un texto y no un número. Por eso en el examen hay que leer bien si te preguntan por errores de buena formación o de validez. Las cinco entidades predefinidas de XML son < (<), > (>), & (&), " (") y ' ('). Si tienes mucho texto con símbolos, puedes envolverlo en una sección <![CDATA[ ... ]]>, donde el analizador no interpreta nada. Y la declaración <?xml ... ?> es opcional, pero si la pones tiene que ser lo primero del fichero: ni siquiera puede haber un espacio o una línea en blanco antes.
2. Escribir la DTD de un documento
Enunciado: escribe una DTD externa para biblioteca.xml. Un libro tiene un título, uno o varios autores, un año, un precio y, opcionalmente, una marca de prestado. Cada libro tiene un identificador único obligatorio y un género que solo puede ser novela, ensayo o técnico.
<!ELEMENT biblioteca (libro+)>
<!ELEMENT libro (titulo, autor+, anio, precio, prestado?)>
<!ELEMENT titulo (#PCDATA)>
<!ELEMENT autor (#PCDATA)>
<!ELEMENT anio (#PCDATA)>
<!ELEMENT precio (#PCDATA)>
<!ELEMENT prestado EMPTY>
<!ATTLIST libro
id ID #REQUIRED
genero (novela | ensayo | tecnico) #REQUIRED>
Y en el XML, justo después de la declaración, se enlaza con:
<!DOCTYPE biblioteca SYSTEM "biblioteca.dtd">
Paso a paso:
- El orden importa. La coma significa "en este orden".
(titulo, autor+, anio, precio, prestado?)obliga a que el título vaya antes que los autores. Si el orden diera igual, la DTD no tiene una forma cómoda de decirlo: habría que usar|con*, que deja de controlar cuántas veces aparece cada uno. - La cardinalidad va pegada a cada elemento. Sin símbolo, exactamente una vez;
?, cero o una;*, cero o más;+, una o más.libro+exige al menos un libro yprestado?lo hace opcional. #PCDATAes texto. Un elemento(#PCDATA)solo contiene texto, sin otros elementos dentro.EMPTYes un elemento que no puede tener contenido, como<prestado/>.- Los atributos van en
ATTLIST.IDobliga a que el valor sea único en todo el documento, y además tiene que ser un nombre XML válido: puede empezar por letra o guion bajo, pero no por número. La lista(novela | ensayo | tecnico)restringe los valores posibles.
Ahora el mismo libro, bien formado pero no válido con esta DTD:
<libro id="5" genero="poesia">
<anio>1963</anio>
<titulo>Rayuela</titulo>
<precio>18.00</precio>
</libro>
Falla por cuatro motivos: id="5" empieza por número y no es un ID válido; poesia no está en la lista de géneros; anio va antes que titulo; y falta al menos un autor.
Lo que hay que entender: una DTD no tiene tipos de dato. Para ella, <anio>mil novecientos</anio> y <precio>gratis</precio> son tan correctos como 1967 y 22.50, porque todo es #PCDATA. Si el enunciado pide que el año sea un número o que el precio no sea negativo, necesitas un XSD. El resto de valores por defecto de un atributo que preguntan: #IMPLIED es opcional, #FIXED "valor" obliga a que sea ese valor y un valor entre comillas sin más es el valor por defecto si no se escribe. IDREF es un atributo que tiene que coincidir con algún ID del documento, y IDREFS, con varios separados por espacios. Si la DTD va dentro del XML (<!DOCTYPE biblioteca [ ... ]>) se llama interna, y si va en un fichero aparte, externa.
3. Escribir el XML Schema (XSD)
Enunciado: escribe un XSD para el mismo documento con estas restricciones adicionales: el identificador tiene el formato L seguido de números, el año es un entero entre 1450 y 2100, y el precio es un decimal no negativo con como mucho dos decimales.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="biblioteca">
<xs:complexType>
<xs:sequence>
<xs:element name="libro" type="tipoLibro" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="tipoLibro">
<xs:sequence>
<xs:element name="titulo" type="xs:string"/>
<xs:element name="autor" type="xs:string" maxOccurs="unbounded"/>
<xs:element name="anio" type="tipoAnio"/>
<xs:element name="precio" type="tipoPrecio"/>
<xs:element name="prestado" minOccurs="0">
<xs:complexType/>
</xs:element>
</xs:sequence>
<xs:attribute name="id" type="tipoId" use="required"/>
<xs:attribute name="genero" type="tipoGenero" use="required"/>
</xs:complexType>
<xs:simpleType name="tipoId">
<xs:restriction base="xs:ID">
<xs:pattern value="L[0-9]+"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="tipoAnio">
<xs:restriction base="xs:integer">
<xs:minInclusive value="1450"/>
<xs:maxInclusive value="2100"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="tipoPrecio">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="tipoGenero">
<xs:restriction base="xs:string">
<xs:enumeration value="novela"/>
<xs:enumeration value="ensayo"/>
<xs:enumeration value="tecnico"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Para enlazarlo, la raíz del XML queda así (y se quita el DOCTYPE):
<biblioteca xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="biblioteca.xsd">
Paso a paso:
simpleTypeocomplexType. Un tipo simple es solo un valor, sin hijos ni atributos: el año, el precio, el género. Un tipo complejo tiene elementos hijos, atributos o las dos cosas: el libro y la biblioteca.<prestado/>es complejo aunque esté vacío, porque uncomplexTypesin contenido es justo la forma de declarar un elemento vacío.- La cardinalidad se escribe con
minOccursymaxOccurs. Por defecto los dos valen 1.maxOccurs="unbounded"equivale al+de la DTD;minOccurs="0", al?; y las dos juntas, al*. - Las restricciones se llaman facetas. Las que más salen:
minInclusive,maxInclusive,minExclusive,maxExclusive,enumeration,pattern,length,minLength,maxLength,totalDigitsyfractionDigits. - Los atributos se declaran después del
sequence, dentro delcomplexType, y son opcionales salvo que pongasuse="required".
Lo que hay que entender: la ventaja del XSD sobre la DTD es que tiene tipos de dato (xs:integer, xs:decimal, xs:date, xs:boolean...), restricciones sobre los valores, soporte para espacios de nombres y, además, está escrito en XML. Con este esquema, el <precio>Menos de 20 € & envío gratis</precio> del ejercicio 1 ya no es válido. Además de xs:sequence (en orden), existen xs:choice (solo uno de los elementos) y xs:all (todos, en cualquier orden, cada uno como mucho una vez). Definir los tipos con nombre, como aquí, en vez de anidarlos dentro de cada elemento, hace el esquema más corto y es lo que suelen valorar los profesores.
4. Consultas XPath
Enunciado: escribe las expresiones XPath que devuelven lo que se pide y su resultado sobre biblioteca.xml.
| Se pide | XPath | Resultado |
|---|---|---|
| Títulos de todos los libros | /biblioteca/libro/titulo |
Los cuatro títulos |
| Títulos de las novelas | //libro[@genero='novela']/titulo |
Cien años de soledad, La sombra del viento |
| Títulos de los libros de más de 20 € | //libro[precio > 20]/titulo |
Cien años de soledad, Patrones de diseño, Sapiens |
| Títulos de los libros prestados | //libro[prestado]/titulo |
Patrones de diseño, La sombra del viento |
| Títulos de los libros disponibles | //libro[not(prestado)]/titulo |
Cien años de soledad, Sapiens |
| Novelas anteriores al año 2000 | //libro[@genero='novela' and anio < 2000]/titulo |
Cien años de soledad |
| Primer autor del segundo libro | /biblioteca/libro[2]/autor[1] |
Erich Gamma |
| Título del último libro | /biblioteca/libro[last()]/titulo |
La sombra del viento |
| Libros con título que contiene "del" | //libro[contains(titulo, 'del')]/titulo |
La sombra del viento |
| Número de libros con más de un autor | count(//libro[count(autor) > 1]) |
1 |
| Género del libro de Harari | //libro[autor='Yuval Noah Harari']/@genero |
ensayo |
| Título del libro cuyo autor es Erich Gamma, subiendo desde el autor | //autor[.='Erich Gamma']/../titulo |
Patrones de diseño |
La trampa que siempre cae: //autor[1] y (//autor)[1] no son lo mismo.
//autor[1]devuelve el primer autor de cada libro: García Márquez, Gamma, Harari y Ruiz Zafón. El predicado[1]se aplica a los hijos de cada padre.(//autor)[1]reúne primero todos los autores del documento en una lista y luego coge el primero: solo García Márquez.
Lo que hay que entender: una ruta que empieza por / es absoluta y parte de la raíz del documento; // busca a cualquier profundidad; @ selecciona atributos; . es el nodo actual y .. el padre. Lo que va entre corchetes es un predicado: filtra los nodos del paso en el que está escrito, no el resultado final. Por eso //libro[precio > 20]/titulo filtra libros y luego saca sus títulos, mientras que //libro/titulo[precio > 20] no devuelve nada, porque un título no tiene hijo precio. Cuando comparas un elemento con un número, XPath convierte su texto a número, por eso precio > 20 funciona. Los ejes con nombre completo también se preguntan: child::, parent::, ancestor::, descendant::, following-sibling::, preceding-sibling:: y attribute:: (de este, @ es la abreviatura).
5. Transformar XML en una tabla HTML con XSLT
Enunciado: escribe una hoja XSLT que genere una página HTML con una tabla de los libros ordenados por año, con los autores separados por comas y una columna que indique si el libro está prestado o disponible. Debajo de la tabla, muestra el total de libros.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Catálogo de la biblioteca</title>
</head>
<body>
<h1>Catálogo de la biblioteca</h1>
<table border="1">
<tr>
<th>Título</th>
<th>Autores</th>
<th>Año</th>
<th>Precio</th>
<th>Estado</th>
</tr>
<xsl:for-each select="biblioteca/libro">
<xsl:sort select="anio" data-type="number" order="ascending"/>
<tr>
<td><xsl:value-of select="titulo"/></td>
<td>
<xsl:for-each select="autor">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">, </xsl:if>
</xsl:for-each>
</td>
<td><xsl:value-of select="anio"/></td>
<td><xsl:value-of select="precio"/> €</td>
<td>
<xsl:choose>
<xsl:when test="prestado">Prestado</xsl:when>
<xsl:otherwise>Disponible</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:for-each>
</table>
<p>Total de libros: <xsl:value-of select="count(biblioteca/libro)"/></p>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
El resultado es una tabla con estas filas:
| Título | Autores | Año | Precio | Estado |
|---|---|---|---|---|
| Cien años de soledad | Gabriel García Márquez | 1967 | 22.50 € | Disponible |
| Patrones de diseño | Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides | 1994 | 45.00 € | Prestado |
| La sombra del viento | Carlos Ruiz Zafón | 2001 | 19.90 € | Prestado |
| Sapiens | Yuval Noah Harari | 2011 | 24.90 € | Disponible |
Y debajo, "Total de libros: 4".
Paso a paso:
- La plantilla
match="/"se ejecuta una vez sobre la raíz del documento y es la que escribe el esqueleto de la página. - Dentro de un
for-eachlas rutas son relativas al nodo actual. Dentro debiblioteca/libro,tituloes el título de ese libro. Escribir/biblioteca/libro/tituloahí dentro es el error más típico: devuelve siempre el primer título del documento, porquevalue-ofen XSLT 1.0 se queda con el primer nodo. xsl:sortva el primero dentro delfor-each. Sindata-type="number"ordena como texto, y con años de cuatro cifras no se nota, pero con precios sí: como texto, "100" va antes que "20".xsl:ifno tieneelse. Para una alternativa se usaxsl:chooseconxsl:whenyxsl:otherwise.position()ylast()dan la posición del nodo actual y el número total de nodos que recorre elfor-each; con ellos se evita la coma después del último autor.
Lo que hay que entender: la otra forma de escribir esto es con xsl:apply-templates y una plantilla match="libro" que pinte cada fila. Si usas apply-templates y no hay plantilla para algún nodo, XSLT aplica sus plantillas por defecto, que copian el texto de los elementos a la salida: por eso a veces aparece texto suelto que nadie ha pedido. Para enlazar la hoja desde el XML se añade <?xml-stylesheet type="text/xsl" href="biblioteca.xsl"?> después de la declaración, pero no te fíes del navegador para probarlo: los navegadores están retirando el soporte de XSLT y Chrome no lo aplica a ficheros abiertos desde el disco. Es más fiable ejecutar xsltproc biblioteca.xsl biblioteca.xml > catalogo.html, usar Saxon o la herramienta que os indiquen en clase.
6. Consultas FLWOR con XQuery
Enunciado: con XQuery, a) devuelve los libros de más de 20 € ordenados de más caro a más barato, con su título y su precio como atributos; b) devuelve cuántos libros hay de cada género.
a) Libros de más de 20 €:
for $libro in doc("biblioteca.xml")/biblioteca/libro
where $libro/precio > 20
order by xs:decimal($libro/precio) descending
return <libro titulo="{$libro/titulo}" precio="{$libro/precio}"/>
Resultado:
<libro titulo="Patrones de diseño" precio="45.00"/>
<libro titulo="Sapiens" precio="24.90"/>
<libro titulo="Cien años de soledad" precio="22.50"/>
b) Libros por género:
for $genero in distinct-values(doc("biblioteca.xml")//libro/@genero)
let $libros := doc("biblioteca.xml")//libro[@genero = $genero]
order by $genero
return <genero nombre="{$genero}" total="{count($libros)}"/>
Resultado:
<genero nombre="ensayo" total="1"/>
<genero nombre="novela" total="2"/>
<genero nombre="tecnico" total="1"/>
Lo que hay que entender: FLWOR son las iniciales de las cláusulas, en este orden: for (recorre una secuencia), let (asigna una variable sin recorrer), where (filtra), order by (ordena) y return (construye el resultado). La diferencia entre for y let es la pregunta estrella: for $l in //libro repite el resto una vez por libro, mientras que let $l := //libro guarda los cuatro libros en una sola variable y el resto se ejecuta una vez. Las llaves { } dentro de un elemento o un atributo indican que lo de dentro es una expresión que hay que evaluar; sin ellas, saldría el texto literal $libro/titulo. El xs:decimal del order by no es decoración: si el documento no está validado contra un esquema, sin él los precios se ordenan como texto. Aquí da igual por casualidad, pero un libro de 100 € quedaría por debajo de uno de 45 €. Para practicar, BaseX es gratuito y permite ejecutar consultas sobre un fichero en segundos; en algunos centros se usa eXist-db.
Preguntas de test típicas de Lenguajes de Marcas
Son las preguntas cortas que más se repiten en exámenes y en cuestionarios tipo Daypo.
| DTD | XML Schema (XSD) | |
|---|---|---|
| Sintaxis | Propia, no es XML | Es un documento XML |
| Tipos de dato | No: todo es texto | Sí: enteros, decimales, fechas, booleanos y tipos propios |
| Restricciones sobre valores | Solo listas de valores en atributos | Rangos, patrones, longitudes, decimales, enumeraciones |
| Cardinalidad | ?, *, + |
minOccurs y maxOccurs con cualquier número |
| Espacios de nombres | No los soporta bien | Sí |
| Entidades | Sí (<!ENTITY>) |
No |
| Modificador XSD o DTD | Equivale a |
|---|---|
Sin símbolo / minOccurs="1" maxOccurs="1" |
Exactamente una vez |
? / minOccurs="0" |
Cero o una vez |
* / minOccurs="0" maxOccurs="unbounded" |
Cero o más veces |
+ / maxOccurs="unbounded" |
Una o más veces |
- ¿Qué es un lenguaje de marcas? Un lenguaje que añade etiquetas a un texto para describir su estructura o su presentación. No es un lenguaje de programación: no tiene variables, bucles ni condiciones (XSLT y XQuery sí los tienen, y por eso se consideran lenguajes de transformación y de consulta).
- ¿HTML o XML? HTML tiene un conjunto fijo de etiquetas pensado para mostrar contenido en el navegador y es tolerante con los errores. XML no tiene etiquetas predefinidas, las defines tú para describir datos, y es estricto: un error y el documento no se procesa. XHTML es HTML escrito con las reglas de XML.
- ¿Qué es un espacio de nombres? Un identificador, normalmente con forma de URI, que se asocia a un prefijo (
xs:,xsl:) para distinguir elementos que se llaman igual pero vienen de vocabularios distintos. La URI no tiene que existir como página web: solo identifica. - ¿Elemento o atributo? Por convención, los datos van en elementos y los metadatos (identificadores, tipos, unidades) en atributos. Un atributo no puede repetirse en el mismo elemento ni contener otros elementos.
- ¿
#PCDATAoCDATA?#PCDATAes el contenido de texto de un elemento en una DTD y el analizador lo interpreta.CDATAes el tipo de un atributo de texto libre en la DTD. Y una sección<![CDATA[ ... ]]>es un bloque de texto que el analizador no interpreta. - ¿Qué elementos son obligatorios en RSS 2.0? El
channeltiene que llevartitle,linkydescription. Cadaitemtiene que tener al menostitleodescription. Atom es el formato alternativo, más estricto y estandarizado por la IETF. - ¿Qué tipos de datos tiene JSON? Cadena (siempre entre comillas dobles), número, booleano,
null, objeto y array. Las claves van entre comillas dobles y no admite comentarios. Frente a XML es más ligero y se lee directamente desde JavaScript, pero no tiene atributos ni espacios de nombres. - ¿Cómo se calcula la especificidad en CSS? Un estilo en línea gana a todo lo demás; después cuentan los selectores de id, luego los de clase, atributo y pseudoclase, y por último los de elemento. A igual especificidad, gana la regla que aparece después.
!importantpasa por encima del orden normal y conviene evitarlo. - ¿Qué es el modelo de caja? Cada elemento es una caja con contenido,
padding,borderymargin. Conbox-sizing: content-box(el valor por defecto) elwidthsolo mide el contenido; conborder-boxincluye también elpaddingy el borde. - ¿Qué es un ERP y qué es un CRM? Un ERP integra la gestión de toda la empresa: contabilidad, compras, ventas, inventario, recursos humanos. Un CRM se centra en la relación con los clientes: contactos, oportunidades de venta, seguimiento comercial. Odoo es un ERP de código abierto que incluye un módulo de CRM, y es el que se usa en la mayoría de centros.
Los errores que más suspenden en Lenguajes de Marcas
Son los que más vemos cuando un alumno nos enseña un examen corregido o una práctica que no valida.
Confundir bien formado con válido. Si te piden los errores de buena formación, no apuntes que falta un elemento obligatorio de la DTD, y al revés.
Las mayúsculas. <Libro> y </libro> no se cierran entre sí, y en XPath //Libro no encuentra ningún <libro>. En papel no hay validador que te avise.
Un ID que empieza por número. id="1" no es válido como ID en una DTD ni como xs:ID en un XSD. Usa una letra delante: L1, A1.
Olvidar el orden de la DTD. La coma obliga al orden. Si el XML tiene los elementos en otro orden, no valida, aunque estén todos.
Usar + cuando era *. "Puede tener varios teléfonos" no dice que tenga que tener al menos uno. Lee el enunciado buscando las palabras "opcional", "al menos uno" y "como mucho".
Rutas absolutas dentro de un for-each. Dentro del bucle, la ruta es relativa al nodo actual. Si empiezas por /, sacas siempre el primer elemento del documento.
Ordenar números como texto. En xsl:sort falta data-type="number" o en XQuery falta convertir el valor, y 100 aparece antes que 20.
El predicado en el sitio equivocado. //libro[precio > 20]/titulo no es lo mismo que //libro/titulo[precio > 20]. El filtro va en el paso del nodo que tiene el dato.
No probar nada en el ordenador. Escribir el XSD en papel sin haberlo validado nunca contra un documento real hace que los errores se repitan en el examen. Valida siempre tus prácticas antes de entregarlas.
Cómo prepararlo
Trabaja siempre con un documento propio. Inventa un XML de algo que conozcas (tu equipo de fútbol, tu colección de videojuegos, los módulos del ciclo) y escríbele una DTD, un XSD, diez consultas XPath, una transformación XSLT y dos consultas XQuery. Es exactamente lo que piden en el examen, y con un documento que entiendes, cada error se ve antes.
Valida en el ordenador lo que haces en papel. VS Code con la extensión XML de Red Hat marca los errores de buena formación y valida contra DTD y XSD al escribir. Desde la terminal tienes xmllint --noout --dtdvalid biblioteca.dtd biblioteca.xml y xmllint --noout --schema biblioteca.xsd biblioteca.xml. XML Copy Editor es otra opción gratuita que se usa en muchos centros.
Prueba XPath antes de escribirlo en XSLT. BaseX y la mayoría de editores XML permiten evaluar una expresión XPath sobre el documento y ver qué nodos devuelve. Si la ruta funciona sola, el fallo de la hoja está en otra parte.
No dejes HTML y CSS para el final. Suele ser la parte que se ve más fácil y la que más puntos regala en la práctica. Haz una página con formulario, tabla y diseño responsive con Flexbox, y la tendrás para siempre. Si eres de DAW, en segundo la necesitarás para JavaScript en Desarrollo Web en Entorno Cliente.
Repasa la teoría con preguntas cortas. Los cuestionarios de Daypo sirven para repasar DTD frente a XSD, RSS, JSON y ERP, pero los crean otros usuarios y algunas respuestas están mal marcadas: contrasta con tus apuntes lo que no te cuadre.
Si eres de DAM, piensa en segundo. El XML de este módulo vuelve en Acceso a Datos, donde lo leerás y escribirás desde Java con DOM y SAX, y en Desarrollo de Interfaces, donde las ventanas de JavaFX se describen en FXML, que también es XML.
Cuándo pedir ayuda
Si escribes la DTD y el XSD sin mirar los apuntes y te validan a la primera, vas bien. Merece la pena buscar ayuda cuando:
- Te dan un XML y no sabes por dónde empezar a escribir su esquema, o lo escribes y no valida y no entiendes el mensaje de error.
- Tus consultas XPath devuelven otros nodos o nada, y no ves por qué.
- La hoja XSLT genera la página vacía, repite siempre el mismo dato o saca texto que nadie ha pedido.
- Programación y Bases de Datos tampoco van bien y Lenguajes de Marcas se te está quedando atrás porque no le dedicas tiempo. Tienes una visión general del curso en si es difícil DAM o DAW.
En nuestras clases de refuerzo para DAM y DAW y en las clases para ASIR y ASIX trabajamos sobre tus enunciados y tus prácticas: escribes tú el esquema o la consulta, lo validamos juntos y vemos por qué falla, para que en el examen sepas hacerlo solo. Son clases online uno a uno a 25 € la hora, sin matrícula ni permanencia.
Preguntas frecuentes
¿Qué es Lenguajes de Marcas?
Es el módulo 0373, Lenguajes de Marcas y Sistemas de Gestión de Información, que se da en primer curso de los ciclos de DAM, DAW y ASIR. Enseña a estructurar información con lenguajes de marcas (HTML, CSS y XML), a validarla con DTD y XML Schema, a consultarla y transformarla con XPath, XSLT y XQuery, a crear canales RSS y a usar sistemas de gestión empresarial como Odoo.
¿Es difícil Lenguajes de Marcas?
Suele ser de los módulos más llevaderos de primero, porque no hace falta saber programar para la mayor parte del temario. Lo que cuesta es la precisión: XML no tolera errores y en el examen no tienes un validador que te avise. Donde más gente se atasca es en XSLT y en XPath con predicados, que son lo más parecido a programar de todo el módulo.
¿Qué diferencia hay entre DTD y XSD?
Las dos sirven para validar un XML, pero una DTD tiene su propia sintaxis y no tiene tipos de dato, mientras que un XSD está escrito en XML, tiene tipos (enteros, decimales, fechas) y permite restringir los valores con rangos, patrones y listas. Una DTD te dice que el año es texto; un XSD te puede decir que es un entero entre 1450 y 2100.
¿Qué programa uso para hacer las prácticas?
Para escribir y validar XML, DTD y XSD: VS Code con la extensión XML de Red Hat, XML Copy Editor o el editor que use tu centro. Para XPath y XQuery, BaseX. Para XSLT, xsltproc desde la terminal o Saxon. Para HTML y CSS basta con VS Code y el navegador.
¿Se convalida Lenguajes de Marcas entre DAM, DAW y ASIR?
Sí. Es el mismo módulo con el mismo código (0373) en los tres ciclos, así que si lo apruebas en uno no tienes que volver a cursarlo en otro; lo pides en la secretaría del centro al matricularte. Entre DAM y DAW se convalidan también los demás módulos comunes de primero, como Programación, Bases de Datos o Entornos de Desarrollo.