XML¶
Introducción¶
Los lenguajes de marcas como HTML tienen una orientación muy clara: describir páginas web.
En un contexto distinto, muy a menudo ocurre que es muy difícil intercambiar datos entre programas.
XML es un conjunto de tecnologías orientadas a crear nuestros propios lenguajes de marcas. A estos lenguajes de marcas «propios» se les denomina «vocabularios».
Un ejemplo sencillo¶
<?xml version="1.0" encoding="UTF-8"?>
<clientes>
<cliente>
<nombre>AcerSA</nombre>
<cif>5664332</cif>
</cliente>
<cliente>
<nombre>Mer SL</nombre>
<cif>5111444</cif>
</cliente>
</clientes>
Lo fundamental es que podemos crear nuestros propios «vocabularios» XML.
Construcción de XML¶
Para crear XML es importante recordar una serie de reglas:
XML es «case-sensitive», es decir que no es lo mismo mayúsculas que minúsculas y que por tanto no es lo mismo
<cliente>
, que<Cliente>
que<CLIENTE>
.Obligatorio: solo un elemento raíz.
En general, la costumbre es poner todo en minúsculas.
Solo se puede poner una etiqueta que empiece por letra o _. Es decir, esta etiqueta no funcionará en los programas
<12Cliente>
.Aparte de eso, una etiqueta sí puede contener números, por lo que esta etiqueta sí es válida
<Cliente12>
.Aunque no es obligatorio a menudo se suele poner en la primera línea un prólogo que indica la versión de XML que estamos usando y la codificación con la que nuestro editor almacena los archivos.
Validez¶
Un documento XML puede «estar bien formado» o «ser válido». Se dice que un documento «está bien formado» cuando respeta las reglas XML básicas. Si alguien ha definido las reglas XML para un vocabulario, podremos además decir si el documento es válido o no, lo cual es mejor que simplemente estar bien formado.
Por ejemplo, los siguientes archivos ni siquiera están bien formados.
<clientes>
<cliente>
<nombre>AcerSA
<CIF>5666333</CIF>
</cliente>
</clientes>
En este caso la etiqueta <nombre>
no está cerrada.
<clientes>
<cliente>
<nombre>AcerSA</nombre>
<cif>5666333</CIF>
</cliente>
</clientes>
En este caso, se ha puesto <cif>
cerrado con </CIF>
(mayúsculas).
<clientes>
<cliente>
<nombre!>AcerSA</nombre!>
<CIF>5666333</CIF>
</cliente>
</clientes>
Se ha utilizado la admiración, que no es válida (de hecho, el coloreador de sintaxis automático descubre que no es XML y el fichero se muestra de manera literal)
Atención a este ejemplo:
<cliente>
<nombre>AcerSA</nombre>
<CIF>5666333</CIF>
</cliente>
<cliente>
<nombre>ACME</nombre>
<CIF>455321</CIF>
</cliente>
En este caso, el problema es que hay más de un elemento raíz.
En general, podemos asumir que un documento puede estar en uno de estos estados que de peor a mejor podríamos indicar así:
Mal formado (lo peor)
Bien formado.
Válido: está bien formado y además nos han dado las reglas para determinar si algo está bien o mal y el documento XML cumple dichas reglas. Este es el mejor caso.
Para determinar si un documento es válido o no, se puede usar el validador del W3C situado en http://validator.w3c.org
Gramáticas¶
Pensemos en el siguiente problema, un programador crea aplicaciones con documentos que se almacenan así:
<clientes>
<cliente>
<nombre>AcerSA</nombre>
<cif>455321</cif>
</cliente>
<cliente>
<nombre>ACME</nombre>
<cif>455321</cif>
</cliente>
</clientes>
Sin embargo, otro programador de la misma empresa lo hace así:
<clientes>
<cliente>
<cif>455321</cif>
<nombre>AcerSA</nombre>
</cliente>
<cliente>
<cif>455321</cif>
<nombre>ACME</nombre>
</cliente>
</clientes>
Está claro, que ninguno de los dos puede leer los archivos del otro, sería crítico ponerse de acuerdo en lo que se puede hacer, lo que puede aparecer y en qué orden debe hacerlo. Esto se hará mediante las DTD.
DTD significa Declaración de Tipo de Documento, y es un mecanismo para expresar las reglas sobre lo que se va a permitir y lo que no en archivos XML.
Por ejemplo, supongamos el mismo ejemplo ejemplo anterior en el que queremos formalizar lo que puede aparecer en un fichero de clientes. Se debe tener en cuenta que en un DTD se pueden indicar reglas para lo siguiente:
Se puede indicar si un elemento aparece o no de forma opcional (usando
?
)Se puede indicar si un elemento debe aparecer de forma obligatoria.
Se puede indicar si algo aparecer una o muchas veces (usando
+
).Se puede indicar si algo aparece cero o muchas veces (usando
*
).Se puede indicar que un elemento ya no lleva nada dentro usando
<!ELEMENT cantidad (#PCDATA)
.Se puede indicar que un elemento cantidad lleva obligatoriamente un atributo divisa usando
<!ATTLIST cantidad divisa CDATA #REQUIRED
Se puede indicar que un elemento cantidad podría llevar o no obligatoriamente un atributo moneda usando
<!ATTLIST cantidad moneda CDATA #IMPLIED
Supongamos que en nuestros ficheros deseamos indicar que el elemento raíz es <listaclientes>
. Dentro de <listaclientes>
deseamos permitir uno o más elementos <cliente>
. Dentro de <cliente>
todos deberán tener <cif>
y <nombre>
y en ese orden. Dentro de <cliente>
puede aparecer o no un elemento <diasentrega>
para indicar que ese cliente exige un máximo de plazos. Como no todo el mundo usa plazos el <diasentrega>
es optativo.
Por ejemplo, este XML sí es válido:
<listaclientes>
<cliente>
<cif>5676443</cif>
<nombre>Mercasa</nombre>
</cliente>
</listaclientes>
Este también lo es:
<listaclientes>
<cliente>
<cif>5676443</cif>
<nombre>Mercasa</nombre>
<diasentrega>30</diasentrega>
</cliente>
</listaclientes>
Este también:
<listaclientes>
<cliente>
<cif>5676443</cif>
<nombre>Mercasa</nombre>
<diasentrega>30</diasentrega>
</cliente>
<cliente>
<cif>5121554</cif>
<nombre>Acer SL</nombre>
</cliente>
</listaclientes>
Sin embargo, estos no lo son:
<listaclientes>
</listaclientes>
Este archivo no tenía clientes (y era obligatorio al menos uno)
<listaclientes>
<cliente>
<cif>5676443</cif>
<diasentrega>30</diasentrega>
</cliente>
</listaclientes>
Este archivo no tiene nombre de cliente.
<listaclientes>
<cliente>
<nombre>Mercasa</nombre>
<cif>5676443</cif>
</cliente>
<cliente>
<cif>5121554</cif>
<nombre>Acer SL</nombre>
</cliente>
</listaclientes>
En este archivo no se respeta el orden cif, nombre.
Sintaxis DTD¶
Una DTD es como un CSS, puede ir en el mismo archivo XML o puede ir en uno separado. Para poder subirlos al validador, meteremos la DTD junto con el XML.
La primera línea de todo XML debe ser esta:
<?xml version="1.0"?>
Al final del XML pondremos los datos propiamente dichos
<listaclientes>
<cliente>
<nombre>Mercasa</nombre>
<cif>5676443</cif>
</cliente>
<cliente>
<cif>5121554</cif>
<nombre>Acer SL</nombre>
</cliente>
</listaclientes>
La DTD tiene esta estructura
<!DOCTYPE listaclientes [
<!ELEMENT listaclientes (cliente+)>
<!ELEMENT cliente (nombre, cif, diasentrega?)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT cif (#PCDATA)>
<!ELEMENT diasentrega (#PCDATA)>
]
>
Esto significa lo siguiente:
Se establece el tipo de documento
listaclientes
que consta de una serie de elementos (dentro del corchete)Un elemento
listaclientes
consta de uno o más clientes. El signo+
significa «uno o más».Un cliente tiene un nombre y un cif. También puede tener un elemento
diasentrega
que puede o no aparecer (el signo?
significa «0 o 1 veces»).Un
nombre
no tiene más elementos dentro, solo caracteres (#PCDATA
)Un
CIF
solo consta de caracteres.Un elemento
diasentrega
consta solo de caracteres.
La solución completa sería así:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE listaclientes [
<!ELEMENT listaclientes (cliente+)>
<!ELEMENT cliente (nombre, cif, diasentrega?)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT cif (#PCDATA)>
<!ELEMENT diasentrega (#PCDATA)>
]>
<listaclientes>
<cliente>
<nombre>Mercasa</nombre>
<cif>5676443</cif>
</cliente>
<cliente>
<nombre>Acer SL</nombre>
<cif>5121554</cif>
</cliente>
</listaclientes>
Combinaciones de cuantificadores y listas de opciones¶
Hay un problema cuando algunas reglas involucran estructuras complejas. Por ejemplo, sin pensamos en una descripción como : «Dentro de listaventas, primero habrá una secuencia de elementos ventapc y despues ventamonitor» entonces este fichero sí debería aceptarse
<listaventas>
<ventapc>100</ventapc>
<ventapc>300</ventapc>
<ventapc>400</ventapc>
<ventamonitor>200</ventamonitor>
<ventamonitor>400</ventamonitor>
<ventamonitor>500</ventamonitor>
</listaventas>
Y este fichero no debería aceptarse:
Pues bien, la regla sería esta: en ella se pone una secuencia SEGUIDA DE otra secuencia
<!ELEMENT listaventas (ventapc+,ventamonitor+)>
<!ELEMENT ventapc (#PCDATA)>
<!ELEMENT ventamonitor (#PCDATA)>
Supongamos esta otra descripción: «Dentro de listaventas, puede haber cualquier orden de elementos ventapc y ventamonitor, se pueden repetir las veces que hagan falta en cualquier orden e incluso intercalados». Es decir, esto se acepta
<listaventas>
<ventapc>100</ventapc>
<ventapc>300</ventapc>
<ventapc>400</ventapc>
<ventamonitor>200</ventamonitor>
<ventamonitor>400</ventamonitor>
<ventamonitor>500</ventamonitor>
</listaventas>
Pero esto también
<listaventas>
<ventapc>100</ventapc>
<ventamonitor>200</ventamonitor>
<ventapc>300</ventapc>
<ventapc>400</ventapc>
<ventamonitor>400</ventamonitor>
</listaventas>
Pues bien, la DTD sería la siguiente:
<!ELEMENT listaventas (ventapc|ventamonitor)+>
<!ELEMENT ventapc (#PCDATA)>
<!ELEMENT ventamonitor (#PCDATA)>
Compárese con el anterior
<!ELEMENT listaventas (ventapc+, ventamonitor+)>
<!ELEMENT ventapc (#PCDATA)>
<!ELEMENT ventamonitor (#PCDATA)>
El anterior obliga a llevar un orden, pero en el ejercicio se aceptaba el «desorden».
Pregunta: ¿Por qué esto está mal?
<!ELEMENT listaventas (ventapc,ventamonitor)+>
<!ELEMENT ventapc (#PCDATA)>
<!ELEMENT ventamonitor (#PCDATA)>
Está mal porque obliga a «escribir secuencias de parejas ventapc, ventamonitor como en el fichero siguiente».
<listaventas>
<ventapc>100</ventapc>
<ventamonitor>400</ventamonitor>
<ventapc>100</ventapc>
<ventamonitor>400</ventamonitor>
<ventapc>100</ventapc>
<ventamonitor>400</ventamonitor>
</listaventas>
Y esto NO ERA LO QUE SE PEDÍA.
Ahora se exige un fichero en el que pase una de estas dos cosas de acuerdo a esta descripción: «los elementos pueden aparecer en cualquier orden, pero en en fichero solo pueden aparecer ventas o compras».
O sea, que esto sí es válido
<listaventas>
<ventapc>800</ventapc>
<ventamonitor>800</ventamonitor>
</listaventas>
Y esto otro también es válido:
<listaventas>
<comprapc>100</comprapc>
<compramonitor>3000</compramonitor>
</listaventas>
Pero esto no está permitido
<listaventas>
<ventapc>100</ventapc>
<compramonitor>3000</compramonitor>
</listaventas>
Pues bien, la regla es esta:
<!ELEMENT listaventas ( (ventapc |ventamonitor )+ |
(comprapc|compramonitor)+ )>
<!ELEMENT ventapc (#PCDATA)>
<!ELEMENT ventamonitor (#PCDATA)>
<!ELEMENT comprapc (#PCDATA)>
<!ELEMENT compramonitor (#PCDATA)>
Ejemplo de DTD (productos)¶
Se pide un conjunto de reglas en forma de DTD para definir qué se permitirá en los archivos XML de datos de una empresa de fabricación:
La raíz es <productos>
Dentro de productos puede haber <raton> o <teclado> que pueden repetirse e ir en cualquier orden (RRTT, T, TR, TTRR)
Todo <raton> tiene siempre un <codigo> y puede o no tener una <descripción>.
Todo <teclado> tiene siempre un <codigo>, debe llevar siempre una <descripcion> y puede o no tener un <peso>
Elaborar la DTD que formaliza estas reglas.
Analicemos algunas posibilidades para la raíz,por ejemplo esta:
<!ELEMENT productos (raton,teclado)>
Esto está MAL. Exige que dentro de productos haya exactamente un ratón y despues un teclado, y solo uno de cada.
Veamos otra:
<!ELEMENT productos (raton, teclado)+>
También está MAL. Exige que haya raton y despues teclado. Es cierto que permite repetir elementos, pero esa repetición es de la pareja, es decir obligamos a que los ficheros sean así:
<raton>
</raton>
<teclado>
</teclado>
<raton>
</raton>
<teclado>
</teclado>
<raton>
</raton>
<teclado>
</teclado>
Echemos un vistazo a otra posible regla para la raíz:
<!ELEMENT productos (raton, teclado)*>
Esto también está mal. Permite que no haya nada dentro de productos, pero ni siquiera nos hablan de eso.
Veamos otra:
<!ELEMENT productos (raton|teclado)>
Esto también está mal porque nos ofrece que dentro de «productos» haya un ratón o un teclado. Es cierto que ofrece algo de flexibilidad, pero aún no es lo que queremos.
Otra regla raíz equivocada sería esta:
<!ELEMENT productos (raton+|teclado+)>
Esto también está mal. Permite que dentro de productos haya una sola de estas cosas
O una secuencia de «raton»
O una secuencia de «teclado»
¡Pero no permite secuencias con mezcla!
Veamos, ahora sí, una solución correcta
<!ELEMENT productos (raton|teclado)* >
<!ELEMENT raton (codigo, descripcion?) >
<!ELEMENT codigo (#PCDATA)>
<!ELEMENT descripcion (#PCDATA)>
<!ELEMENT teclado (codigo,descripcion,peso?)>
<!ELEMENT peso (#PCDATA)>
El siguiente fichero debe validarse correctamente:
<productos>
</productos>
Y el siguiente también
<productos>
<teclado>
<codigo>T1</codigo>
<descripcion>Teclado inalamb.</descripcion>
</teclado>
</productos>
Y este también (a pesar del flagrante error en el peso)
<productos>
<raton>
<codigo>R1</codigo>
</raton>
<teclado>
<codigo>T1</codigo>
<descripcion>Teclado inalamb.</descripcion>
<peso>|@¬|@~||@~</peso>
</teclado>
</productos>
Ejercicio I (DTD)¶
Unos programadores necesitan un formato de fichero para que sus distintos programas intercambien información sobre ventas. El acuerdo al que han llegado es que su XML debería tener esta estructura:
El elemento raíz será
<listaventas>
Toda
<listaventas>
tiene una o más ventas.Toda
<venta>
tiene los siguientes datos:Importe.
Comprador.
Vendedor.
Fecha (optativa).
Un codigo de factura.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE listaventas[
<!ELEMENT listaventas (venta+)>
<!ELEMENT venta (importe, comprador, vendedor, fecha?, codigofactura)>
<!ELEMENT importe (#PCDATA)>
<!ELEMENT comprador (#PCDATA)>
<!ELEMENT vendedor (#PCDATA)>
<!ELEMENT fecha (#PCDATA)>
<!ELEMENT codigofactura (#PCDATA)>
]>
<listaventas>
<venta>
<importe>1500</importe>
<comprador>Wile E.Coyote</comprador>
<vendedor>ACME</vendedor>
<codigofactura>E17</codigofactura>
</venta>
<venta>
<importe>750</importe>
<comprador>Elmer Fudd</comprador>
<vendedor>ACME</vendedor>
<fecha>27-2-2015</fecha>
<codigofactura>E18</codigofactura>
</venta>
</listaventas>
Ejercicio II (DTD)¶
Crear un XML de ejemplo y la DTD asociada para unos programadores que programan una aplicación de pedidos donde hay una lista de pedidos con 0 o más pedidos. Cada pedido tiene un número de serie, una cantidad y un peso que puede ser opcional.
Solución¶
Este ejemplo es un documento XML válido.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE listapedidos [
<!ELEMENT listapedidos (pedido*)>
<!ELEMENT pedido (numeroserie, cantidad, peso?)>
<!ELEMENT numeroserie (#PCDATA)>
<!ELEMENT cantidad (#PCDATA)>
<!ELEMENT peso (#PCDATA)>
]>
<listapedidos>
</listapedidos>
Este documento no es válido
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE listapedidos [
<!ELEMENT listapedidos (pedido*)>
<!ELEMENT pedido (numeroserie, cantidad, peso?)>
<!ELEMENT numeroserie (#PCDATA)>
<!ELEMENT cantidad (#PCDATA)>
<!ELEMENT peso (#PCDATA)>
]>
<listapedidos>
<pedido>
<numeroserie>23332244</numeroserie>
</pedido>
</listapedidos>
Este documento sí es válido. Las DTD solo se ocupan de determinar qué elementos hay y en qué orden, pero no se ocupan de lo que hay dentro de los elementos.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE listapedidos [
<!ELEMENT listapedidos (pedido*)>
<!ELEMENT pedido (numeroserie, cantidad, peso?)>
<!ELEMENT numeroserie (#PCDATA)>
<!ELEMENT cantidad (#PCDATA)>
<!ELEMENT peso (#PCDATA)>
]>
<listapedidos>
<pedido>
<numeroserie>23332244</numeroserie>
<cantidad>ññlñ</cantidad>
</pedido>
</listapedidos>
Ejercicio III¶
Se desea crear una gramática para ficheros de datos en los que se ha decidido contemplar lo siguiente:
El fichero debe llevar una raíz
<productos>
Dentro debe haber uno o más elementos
<producto>
Dentro de productos debe haber alguno de estos
<producto>
,<raton>
,<teclado>
o<monitor>
Todo ratón, teclado o monitor tiene siempre un código.
Todo ratón, teclado o monitor puede llevar un nombre.
Todo ratón, teclado o monitor puede llevar una descripción.
<productos>
<producto>
<raton>
<codigo>27A</codigo>
</raton>
</producto>
<producto>
<teclado>
<codigo>28D</codigo>
<descripcion>Teclado en Español</descripcion>
</teclado>
</producto>
</productos>
Solución al ejercicio III¶
<!ELEMENT productos (producto+)>
<!ELEMENT producto (raton|teclado|monitor)>
<!ELEMENT raton (codigo, nombre?, descripcion?)>
<!ELEMENT teclado (codigo, nombre?, descripcion?)> <!ELEMENT monitor (codigo, nombre?, descripcion?)>
<!ELEMENT codigo (#PCDATA)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT descripcion (#PCDATA)>
Ejercicio IV¶
Unos programadores necesitan un formato de fichero para que sus distintos programas intercambien información sobre ventas. El acuerdo al que han llegado es que su XML debería tener esta estructura:
El elemento raíz será <listaventas>
Toda <listaventas> tiene una o más <venta>.
- Toda <venta> tiene los siguientes datos:
Importe.
Comprador.
Vendedor.
Fecha (optativa).
Un codigo de factura.
Solución al ejercicio IV¶
Por ahora no se dará la solución de este ejercicio. Inténtalo y si no puedes pide ayuda al profesor o escríbele un email para averiguar como resolverlo.
Ejercicio V DTD¶
En un departamento se ha decidido la siguiente estructura para ficheros de datos que se tengan que mover de unos software a otros.
La raíz debe ser el elemento
<listacompras>
Dentro de
<listacompras>
debe haber uno o más elementos<venta>
Una
venta
puede llevar dentro uno de dos:<ventaacredito>
o<ventainmediata>
Un elemento
<ventaacredito>
consta de : un elemento<fechafinpago>
que es optativo y un elemento<cantidad>
que es obligatorio.Un elemento
<ventainmediata>
lleva dentro dos cosas: un elemento<cantidad>
que es obligatorio y un elemento<divisa>
que también es obligatorio.
Solución al ejercicio V¶
Puedes usar este ejemplo para hacer la validación:
<listacompras>
<venta>
<ventaacredito>
<fechafinpago>22-10-2021</fechafinpago>
<cantidad>21000</cantidad>
</ventaacredito>
</venta>
<venta>
<ventainmediata>
<cantidad>1800</cantidad>
<divisa>euros</divisa>
</ventainmediata>
</venta>
<venta>
<ventaacredito>
<cantidad>21000</cantidad>
</ventaacredito>
</venta>
</listacompras>
<<<<<<< HEAD Una posible solución sería:
<!ELEMENT listacompras (venta+)>
<!ELEMENT venta (ventaacredito|ventainmediata)>
<!ELEMENT ventaacredito (fechafinpago?, cantidad)>
<!ELEMENT ventainmediata (cantidad, divisa)>
<!ELEMENT fechafinpago (#PCDATA)>
<!ELEMENT cantidad (#PCDATA)>
<!ELEMENT divisa (#PCDATA)>
Ejercicio VI DTD¶
Un mayorista de productos de librería desea tener un formato de almacenamiento de datos para reflejar la información de su inventario.
El elemento raíz debe ser
<inventario>
Dentro de inventario pueden ir elementos
<lapiz>
,<cuaderno>
o<boligrafo>
repetidos y en cualquier orden.Todo
<lapiz>
puede tener un elemento<dureza>
Todo cuaderno debe llevar dos elementos:
<numhojas>
y<estilo>
Todo boligrafo lleva un
<precio>
y puede o no llevar un elemento<color>
El siguiente fichero debería ser validado por la DTD:
<inventario>
<lapiz></lapiz>
<lapiz>
<dureza>H2</dureza>
</lapiz>
<cuaderno>
<numhojas>80</numhojas>
<estilo>2 rayas</estilo>
</cuaderno>
<boligrafo>
<precio>0.80</precio>
</boligrafo>
<cuaderno>
<numhojas>100</numhojas>
<estilo>Cuadriculado</estilo>
</cuaderno>
<boligrafo>
<precio>0.80</precio>
<color>Rojo</color>
</boligrafo>
</inventario>
<!ELEMENT inventario (cuaderno|lapiz|boligrafo)+>
<!ELEMENT cuaderno (numhojas,estilo)>
<!ELEMENT numhojas (#PCDATA)>
<!ELEMENT estilo (#PCDATA)>
<!ELEMENT lapiz (dureza?)>
<!ELEMENT dureza (#PCDATA)>
<!ELEMENT boligrafo (precio, color?)>
<!ELEMENT precio (#PCDATA)>
<!ELEMENT color (#PCDATA)>
Ejercicio (con atributos)¶
Unos programadores necesitan estructurar la información que intercambiarán los ficheros de sus aplicaciones para lo cual han determinado los requisitos siguientes.
Los ficheros deben tener un elemento
<listafacturas>
Dentro de la lista debe haber una o más facturas.
Las facturas tienen un atributo
fecha
que es optativo.Toda factura tiene un
emisor
, que es un elemento obligatorio y que debe tener un atributocif
que es obligatorio. Dentro deemisor
debe haber un elementonombre
, que es obligatorio y puede o no haber un elementovolumenventas
.Toda factura debe tener un elemento
pagador
, el cual tiene exactamente la misma estructura queemisor
.Toda factura tiene un elemento
importe
.
Solución ejercicio con atributos¶
La siguiente DTD refleja los requisitos indicados en el enunciado.
<!ELEMENT listafacturas (factura+)>
<!ELEMENT factura (emisor, pagador, importe)>
<!ATTLIST factura fecha CDATA #IMPLIED>
<!ELEMENT emisor (nombre, volumenventas?)>
<!ELEMENT nombre (#PCDATA)>
<!ATTLIST emisor cif CDATA #REQUIRED>
<!ELEMENT volumenventas (#PCDATA)>
<!ELEMENT pagador (nombre, volumenventas?)>
<!ATTLIST pagador cif CDATA #REQUIRED>
<!ELEMENT importe (#PCDATA)>
Y el XML siguiente refleja un posible documento. Puede comprobarse que es válido con respecto a la DTD.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE listafacturas SYSTEM "ListaFacturas.dtd">
<listafacturas>
<factura fecha="11-2-2015">
<emisor cif="123">
<nombre>ACME</nombre>
</emisor>
<pagador cif="234">
<nombre>ACME Inc</nombre>
<volumenventas>2000</volumenventas>
</pagador>
<importe>2500</importe>
</factura>
</listafacturas>
Ejercicio¶
Un instituto necesita registrar los cursos y alumnos que estudian en él y necesita una DTD para comprobar los documentos XML de los programas que utiliza:
Tiene que haber un elemento raíz
listacursos
. Tiene que haber uno o más cursos.Un curso tiene uno o más alumnos
Todo alumno tiene un DNI, un nombre y un apellido, puede que tenga segundo apellido o no.
Un alumno escoge una lista de asignaturas donde habrá una o más asignaturas. Toda asignatura tiene un nombre, un atributo código y un profesor.
Un profesor tiene un NRP (Número de Registro Personal), un nombre y un apellido (también puede tener o no un segundo apellido).
Solución completa¶
<!ELEMENT listacursos (curso)+>
<!ELEMENT curso (alumno)+>
<!ELEMENT alumno (dni, nombre,
ap1, ap2?, listaasignaturas)>
<!ELEMENT listaasignaturas (asignatura+)>
<!ELEMENT asignatura (nombre, profesor)>
<!ATTLIST asignatura codigo CDATA #REQUIRED>
<!ELEMENT profesor (nrp, nombre, ap1, ap2?)>
<!ELEMENT dni (#PCDATA)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT ap1 (#PCDATA)>
<!ELEMENT ap2 (#PCDATA)>
<!ELEMENT nrp (#PCDATA)>
Un ejemplo de fichero válido:
<listacursos>
<curso>
<alumno>
<dni>44e</dni>
<nombre>Juan</nombre>
<ap1>Sanchez</ap1>
<listaasignaturas>
<asignatura codigo="LM1">
<nombre>Leng marcas</nombre>
<profesor>
<nrp>8</nrp>
<nombre>Oscar</nombre>
<ap1>Gomez</ap1>
</profesor>
</asignatura>
</listaasignaturas>
</alumno>
</curso>
</listacursos>
Otras características de XML¶
Atributos¶
Un atributo XML funciona exactamente igual que un atributo HTML, en concreto un atributo es un trozo de información que acompaña a la etiqueta, en lugar de ir dentro del elemento.
<pedido codigo="20C">
<contenido>
...
</pedido>
En este caso, la etiqueta pedido
tiene un atributo codigo
.
¿Cuando debemos usar atributos y cuando debemos usar elementos? Resulta que el ejemplo anterior también se podría haber permitido hacerlo así:
<pedido>
<codigo>20C</codigo>
<contenido>
...
</pedido>
Hay muchas discusiones sobre qué meter dentro de elemento o atributo. Sin embargo, los expertos coinciden en señalar que en caso de duda es mejor el segundo.
La definición de atributos se hace por medio de una directiva llamada ATTLIST
. En concreto si quisieramos permitir un atributo código
en el elemento pedido
se haría algo así.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE pedido[
<!ELEMENT pedido (contenido)>
<!ELEMENT contenido (#PCDATA)>
<!ATTLIST pedido codigo CDATA #REQUIRED>
]>
<pedido codigo="20C">
<contenido>Pedido de cosas</contenido>
</pedido>
En concreto este código pone que el elemento pedido
tiene un atributo código
con datos carácter dentro y que es obligatorio que esté presente (un atributo optativo en vez de #REQUIRED
usará #IMPLIED
)
Si probamos esto, también validará porque el atributo es optativo
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE pedido[
<!ELEMENT pedido (contenido)>
<!ELEMENT contenido (#PCDATA)>
<!ATTLIST pedido codigo CDATA #IMPLIED>
]>
<pedido>
<contenido>Pedido de cosas</contenido>
</pedido>
Elementos vacíos¶
En ocasiones, un elemento en especial puede interesarnos que vaya vacío porque simplemente no contiene mucha información de relevancia. Por ejemplo en HTML podemos encontrarnos esto:
<b>Texto texto...</b>
<br/>
Los elementos vacíos suelen utilizar para indicar pequeñas informaciones que no deseamos meter en atributos y que de todas formas tampoco son de demasiada relevancia.
Un elemento vacío se indica poniendo EMPTY
en lugar de #PCDATA
Por supuesto, estas dos formas de usar un atributo son válidas:
<pedido>
<pagado></pagado>
<contenido>...</contenido>
</pedido>
<pedido>
<pagado/>
<contenido>...</contenido>
</pedido>
La definición completa sería así:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE pedido[
<!ELEMENT pedido (pagado?,contenido)>
<!ELEMENT pagado EMPTY>
<!ELEMENT contenido (#PCDATA)>
<!ATTLIST pedido codigo CDATA #IMPLIED>
]>
<pedido>
<pagado/>
<contenido>Pedido de cosas</contenido>
</pedido>
Alternativas¶
Hasta ahora hemos indicado elementos donde un elemento puede aparecer o puede no aparecer, pero ¿qué ocurre si deseamos obligar a que aparezca una posibilidad entre varias?
Por ejemplo, supongamos que en un nuestro ejemplo de pedidos deseamos indicar si el pedido se entregó en almacén o a domicilio. A la fuerza todo pedido se entrega de alguna manera, sin embargo queremos exigir que en los XML aparezca una de esas dos alternativas. Los elementos alternativos se indican con la barra vertical almacen|domicilio
Una tentación sería hacer esto (que está mal):
<!DOCTYPE pedido[
<!ELEMENT pedido (pagado?, contenido, almacen?,domicilio?)>
<!ELEMENT pagado EMPTY>
<!ELEMENT contenido (#PCDATA)>
<!ELEMENT almacen (#PCDATA)>
<!ELEMENT domicilio (#PCDATA>
]>
Está mal porque se permite esto:
<pedido>
<pagado/>
<contenido>Ordenadores</contenido>
<almacen>Entregado el 20-2-2011</almacen>
<domicilio>Entregado el 20-2011</domicilio>
</pedido>
La forma correcta es esta:
<!DOCTYPE pedido[
<!ELEMENT pedido (pagado?, contenido, (almacen|domicilio)?>
<!ELEMENT pagado EMPTY>
<!ELEMENT contenido (#PCDATA)>
<!ELEMENT almacen (#PCDATA)>
<!ELEMENT domicilio (#PCDATA>
]>
<pedido>
<contenido>Ordenadores</contenido>
</pedido>
Ejercicio¶
Un mayorista informático necesita especificar las reglas de los elementos permitidos en las aplicaciones que utiliza en sus empresas, para ello ha indicado los siguientes requisitos:
Una entrega consta de uno o más lotes.
Un lote tiene uno o más palés
Todo palé tiene una serie de elementos: número de cajas, contenido y peso y forma de manipulación.
El contenido consta de una serie de elementos: nombre del componente, procedencia (puede aparecer 0, 1 o más países), número de serie del componente, peso del componente individual y unidad de peso que puede aparecer o no.
Solución¶
Observa como en la siguiente DTD se pone procedencia?
y dentro de ella pais+
. Esto nos permite que si aparece la procedencia se debe especificar uno o más países. Sin embargo si no queremos que aparezca ningun pais, el XML no necesita contener un elemento vacío.
<!ELEMENT entrega (lote+)>
<!ELEMENT lote (pale+)>
<!ELEMENT pale (numcajas, contenido, peso, formamanipulacion?)>
<!ELEMENT numcajas (#PCDATA)>
<!ELEMENT peso (#PCDATA)>
<!ELEMENT formamanipulacion (#PCDATA)>
<!ELEMENT contenido (nombrecomponente, procedencia?,
numserie, peso, unidades)>
<!ELEMENT nombrecomponente (#PCDATA)>
<!ELEMENT procedencia (pais+)>
<!ELEMENT pais (#PCDATA)>
<!ELEMENT numserie (#PCDATA)>
<!ELEMENT unidades (#PCDATA)>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE entrega SYSTEM "mayorista.dtd">
<entrega>
<lote>
<pale>
<numcajas>3</numcajas>
<contenido>
<nombrecomponente>Fuentes</nombrecomponente>
<numserie>3A</numserie>
<peso>2kg</peso>
<unidades>50</unidades>
</contenido>
<peso>100kg</peso>
<formamanipulacion>Manual</formamanipulacion>
</pale>
</lote>
<lote>
<pale>
<numcajas>2</numcajas>
<contenido>
<nombrecomponente>CPUs</nombrecomponente>
<procedencia>
<pais>China</pais>
<pais>Corea del Sur</pais>
</procedencia>
<numserie>5B</numserie>
<peso>100g</peso>
<unidades>1000</unidades>
</contenido>
<peso>100kg</peso>
<formamanipulacion>Manual</formamanipulacion>
</pale>
</lote>
</entrega>
Ejercicio: mayorista de libros¶
Se desea crear un formato de intercambio de datos para una empresa mayorista de libros con el fin de que sus distintos programas puedan manejar la información interna. El formato de archivo debe tener la siguiente estructura:
El elemento raíz es «operaciones».
Dentro de «operaciones» hay uno o más elementos «operacion».
Una «operacion» puede ser «venta», «compra», o cualquier combinación y secuencia de ellas, pero debe haber al menos una.
Una venta tiene dentro un elemento «titulosvendidos». Dentro de «titulosvendidos» se almacenan estos datos:
Uno o más elementos «título».
La cantidad total de libros vendidos.
Puede haber un elemento «entregado» que indique si la entrega se ha realizado.
Debe haber un elemento importe con un atributo obligatorio llamado «moneda».
Una compra tiene dentro un elemento «tituloscomprados». Dentro de él hay esto:
Uno o más elementos «titulo»
Un «proveedor».
Una fecha de compra, que debe desglosarse en elementos día, mes y año
El objetivo final debe ser validar un fichero como este:
<operaciones>
<operacion>
<venta>
<titulosvendidos>
<titulo>Don Quijote</titulo>
<titulo>Rimas y leyendas</titulo>
<cantidadtotal>2000</cantidadtotal>
<importe moneda="euros">4400</importe>
</titulosvendidos>
</venta>
<venta>
<titulosvendidos>
<titulo>Rinconete y Cortadillo</titulo>
<titulo>Sainetes</titulo>
<cantidadtotal>1000</cantidadtotal>
<entregado/>
<importe moneda="libras">290</importe>
</titulosvendidos>
</venta>
</operacion>
<operacion>
<compra>
<tituloscomprados>
<titulo>De la Tierra a la Luna</titulo>
<titulo>Barbarroja</titulo>
<proveedor>Editorial EDSA</proveedor>
<fechacompra>
<dia>10</dia>
<mes>6</mes>
<anio>2018</anio>
</fechacompra>
</tituloscomprados>
</compra>
<venta>
<titulosvendidos>
<titulo>Cinco semanas en globo</titulo>
<titulo>Sainetes</titulo>
<cantidadtotal>700</cantidadtotal>
<entregado/>
<importe moneda="euros">1490</importe>
</titulosvendidos>
</venta>
<compra>
<tituloscomprados>
<titulo>De la Tierra a la Luna</titulo>
<titulo>Barbarroja</titulo>
<proveedor>Editorial Recopila</proveedor>
<fechacompra>
<dia>2</dia>
<mes>12</mes>
<anio>2017</anio>
</fechacompra>
</tituloscomprados>
</compra>
</operacion>
</operaciones>
Solución al mayorista de libros¶
La siguiente DTD valida el fichero arriba mostrado:
<!--El elemento raíz es operaciones y dentro de él hay uno o más elementos operación-->
<!ELEMENT operaciones (operacion+)>
<!--Una operación puede ser ventas o compras, en cualquier orden y repetidas las veces que sea necesario-->
<!ELEMENT operacion (venta|compra)+>
<!ELEMENT venta (titulosvendidos)>
<!--Una venta tiene uno o más titulos, la cantidad de libros vendidos, puede haber un elemento entregado que indique si la entrega se ha realizado, y debe haber un elemento importe con un atributo obligatorio llamado moneda. -->
<!ELEMENT titulosvendidos (titulo+, cantidadtotal, entregado?, importe)>
<!--Antes de que se nos olvide, fabricamos el elemento importe y su atributo moneda-->
<!ELEMENT importe (#PCDATA)>
<!ATTLIST importe moneda CDATA #REQUIRED>
<!--Fabricamos el titulo y la cantidad total-->
<!ELEMENT titulo (#PCDATA)>
<!ELEMENT cantidadtotal (#PCDATA)>
<!--El elemento entregado parece que es un vacío-->
<!ELEMENT entregado EMPTY>
<!--Una compra tiene:
-Uno o más títulos comprados.
-Nombre de proveedor.
-Una fecha de compra, que debe desglosarse en elementos día, mes y año -->
<!ELEMENT compra (tituloscomprados)>
<!ELEMENT tituloscomprados (titulo+, proveedor, fechacompra)>
<!ELEMENT proveedor (#PCDATA)>
<!--Desglosamos la fecha-->
<!ELEMENT fechacompra (dia, mes, anio)>
<!ELEMENT dia (#PCDATA)>
<!ELEMENT mes (#PCDATA)>
<!ELEMENT anio (#PCDATA)>
Ejercicio: fabricante de tractores¶
Un fabricante de tractores desea unificar el formato XML de sus proveedores y para ello ha indicado que necesita que los archivos XML cumplan las siguientes restricciones:
Un pedido consta de uno o más tractores.
Un tractor consta de uno o más componentes.
Un componente tiene los siguientes elementos: nombre del fabricante (atributo obligatorio), fecha de entrega (si es posible, aunque puede que no aparezca, si aparece el dia es optativo, pero el mes y el año son obligatorios). También se necesita saber del componente si es frágil o no. También debe aparecer un elemento peso del componente y dicho elemento peso tiene un atributo unidad del peso (kilos o gramos), un elemento número de serie y puede que aparezca o no un elemento kmmaximos indicando que el componente debe sustituirse tras un cierto número de kilómetros.
Un posible fichero de ejemplo que podría validar sería este:
<pedido>
<tractor>
<componente nombrefabricante="Ebro">
<fechaentrega>
<mes>2018</mes> <anio>2018</anio>
</fechaentrega>
<fragil/>
<peso unidad="kg">12</peso>
<numserie>00A</numserie>
</componente>
<componente nombrefabricante="Avia">
<fechaentrega>
<dia>12</dia><mes>1</mes><anio>2019</anio>
</fechaentrega>
<nofragil/>
<peso unidad="g">1450</peso>
<numserie>00D</numserie>
<kmmaximos>25000</kmmaximos>
</componente>
</tractor>
<tractor>
<componente nombrefabricante="John Deere">
<fragil/>
<peso unidad="g">770</peso>
<numserie>43Z</numserie>
</componente>
</tractor>
</pedido>
Solución: DTD fabricante tractores¶
<!ELEMENT pedido (tractor)+>
<!ELEMENT tractor (componente)+>
<!ELEMENT componente (fechaentrega?, (fragil|nofragil),
peso, numserie, kmmaximos?)>
<!ELEMENT fechaentrega (dia?, mes, anio)>
<!ELEMENT dia (#PCDATA)>
<!ELEMENT mes (#PCDATA)>
<!ELEMENT anio (#PCDATA)>
<!ELEMENT fragil EMPTY>
<!ELEMENT nofragil EMPTY >
<!ELEMENT peso (#PCDATA)>
<!ATTLIST peso unidad CDATA #REQUIRED>
<!ELEMENT numserie (#PCDATA)>
<!ELEMENT kmmaximos (#PCDATA)>
<!ATTLIST componente nombrefabricante CDATA #REQUIRED>
Ejercicio: repeticiones de opciones¶
Se necesita un formato de archivo para intercambiar productos entre almacenes de productos de librería y se desea una DTD que incluya estas restricciones:
Debe haber un elemento raíz pedido que puede constar de libros, cuadernos y/o lápices. Los tres elementos pueden aparecer repetidos y en cualquier orden. Tambien pueden aparecer por ejemplo 4 libros, 2 lapices y luego 4 lapices de nuevo.
Todo libro tiene un atributo obligatorio titulo.
Los elementos cuaderno tiene un atributo optativo num_hojas.
Todo elemento lápiz debe tener dentro un elemento obligatorio número.
La solución a la DTD:
<!ELEMENT pedido (libro|cuaderno|lapiz)+>
<!ELEMENT libro (#PCDATA)>
<!ATTLIST libro titulo CDATA #REQUIRED>
<!ELEMENT cuaderno (#PCDATA)>
<!ATTLIST cuaderno num_hojas CDATA #IMPLIED>
<!ELEMENT lapiz (numero)>
<!ELEMENT numero (#PCDATA)>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE pedido SYSTEM "libreria.dtd">
<pedido>
<libro titulo="Java 8"></libro>
<cuaderno></cuaderno>
<libro titulo="HTML y CSS"/>
<libro titulo="SQL para Dummies"/>
<cuaderno num_hojas="150"/>
<lapiz>
<numero>2H</numero>
</lapiz>
<cuaderno num_hojas="250"/>
<cuaderno num_hojas="100"/>
<lapiz>
<numero>2B</numero>
</lapiz>
<lapiz>
<numero>1HB</numero>
</lapiz>
</pedido>
Ejercicio: multinacional¶
Una multinacional que opera en bolsa necesita un formato de intercambio de datos para que sus programas intercambien información sobre los mercados de acciones.
En general todo archivo constará de un listado de cosas como se detalla a continuación
En el listado aparecen siempre uno o varios futuros, despues una o varias divisas, despues uno o varios bonos y una o varias letras.
Todos ellos tienen un atributo precio que es obligatorio
Todos ellos tienen un elemento vacío que indica de donde es el producto anterior: «Madrid», «Nueva York», «Frankfurt» o «Tokio».
Las divisas y los bonos tienen un atributo optativo que se usa para indicar si el producto ha sido estable en el pasado o no.
Un futuro es un valor esperado que tendrá un cierto producto en el futuro. Se debe incluir este producto en forma de elemento. También puede aparecer un elemento mercado que indique el país de procedencia del producto.
Todo bono tiene un elemento país_de_procedencia para saber a qué estado pertenece. Debe tener tres elementos extra llamados «valor_deseado», «valor_mínimo» y «valor_máximo» para saber los posibles precios.
Las divisas tienen siempre un nombre pueden incluir uno o más tipos de cambio para otras monedas.
Las letras tienen siempre un tipo de interés pagadero por un país emisor. El país emisor también debe existir y debe ser siempre de uno de los países cuyas capitales aparecen arriba (es decir «España», «EEUU», «Alemania» y «Japón»
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE listado [
<!ELEMENT listado (futuro+, divisa+, bono+, letra+)>
<!ATTLIST futuro precio CDATA #REQUIRED>
<!ATTLIST divisa precio CDATA #REQUIRED>
<!ATTLIST bono precio CDATA #REQUIRED>
<!ATTLIST letra precio CDATA #REQUIRED>
<!ELEMENT ciudad_procedencia (madrid|nyork|frankfurt|tokio)>
<!ELEMENT madrid EMPTY>
<!ELEMENT nyork EMPTY>
<!ELEMENT frankfurt EMPTY>
<!ELEMENT tokio EMPTY>
<!ATTLIST divisa estable CDATA #IMPLIED>
<!ATTLIST bono estable CDATA #IMPLIED>
<!ELEMENT futuro (producto, mercado?, ciudad_procedencia)>
<!ELEMENT producto (#PCDATA)>
<!ELEMENT mercado (#PCDATA)>
<!ELEMENT bono (pais_de_procedencia,valor_deseado,
valor_minimo, valor_maximo, ciudad_procedencia)>
<!ELEMENT valor_deseado (#PCDATA)>
<!ELEMENT valor_minimo (#PCDATA)>
<!ELEMENT valor_maximo (#PCDATA)>
<!ELEMENT pais_de_procedencia (#PCDATA)>
<!ELEMENT divisa (nombre_divisa,
tipo_de_cambio+, ciudad_procedencia)>
<!ELEMENT nombre_divisa (#PCDATA)>
<!ELEMENT tipo_de_cambio (#PCDATA)>
<!ELEMENT letra (tipo_de_interes, pais_emisor,ciudad_procedencia)>
<!ELEMENT tipo_de_interes (#PCDATA)>
<!ELEMENT pais_emisor (espania|eeuu|alemania|japon)>
<!ELEMENT espania EMPTY>
<!ELEMENT eeuu EMPTY>
<!ELEMENT alemania EMPTY>
<!ELEMENT japon EMPTY>
]>
<listado>
<futuro precio="11.28">
<producto>Cafe</producto>
<mercado>América Latina</mercado>
<ciudad_procedencia>
<frankfurt/>
</ciudad_procedencia>
</futuro>
<divisa precio="183">
<nombre_divisa>Libra esterlina</nombre_divisa>
<tipo_de_cambio>2.7:1 euros</tipo_de_cambio>
<tipo_de_cambio>1:0.87 dólares</tipo_de_cambio>
<ciudad_procedencia>
<madrid/>
</ciudad_procedencia>
</divisa>
<bono precio="10000" estable="si">
<pais_de_procedencia>
Islandia
</pais_de_procedencia>
<valor_deseado>9980</valor_deseado>
<valor_minimo>9950</valor_minimo>
<valor_maximo>10020</valor_maximo>
<ciudad_procedencia>
<tokio/>
</ciudad_procedencia>
</bono>
<letra precio="45020">
<tipo_de_interes>4.54%</tipo_de_interes>
<pais_emisor>
<espania/>
</pais_emisor>
<ciudad_procedencia>
<madrid/>
</ciudad_procedencia>
</letra>
</listado>
Otros ejercicios DTD¶
Inventario de piezas¶
Se desea almacenar nombres de piezas y para ello se ha llegado a este acuerdo:
El elemento raíz se va a llamar «listapiezas».
Dentro de «listapiezas» va a haber uno o muchos elementos «pieza»
Dentro de «pieza» hay tres elementos:
1.. Un elemento llamado «peso» que contiene datos 2. Un elemento llamado «nombre» que contiene datos 3. Un elemento llamado fabricante que contiene datos.
El fabricante lleva un atributo llamado pais que indica el pais
Ejemplo de fichero válido:
<listapiezas>
<pieza>
<peso>20</peso>
<nombre>Pistón</nombre>
<fabricante pais="China"> Asia Electronics</fabricante>
</pieza>
<pieza>
<peso>15</peso>
<nombre>Cilindro</nombre>
<fabricante pais="Japón">Toyota Motors</fabricante>
</pieza>
</listapiezas>
Ejemplo de fichero que debe dar errores
<listapiezas>
<pieza>
<peso>20</peso>
<nombre>Pistón</nombre>
<!--Aquí falta el país-->
<fabricante> Asia Electronics</fabricante>
</pieza>
<pieza>
<peso>15</peso>
<!--Aquí falta el nombre-->
<fabricante pais="Japón">Toyota Motors</fabricante>
</pieza>
</listapiezas>
Una posible solución sería esta:
.. code-block:: dtd
<!ELEMENT listapiezas (pieza+)> <!ELEMENT pieza (peso, nombre,fabricante)> <!ELEMENT peso (#PCDATA)> <!ELEMENT nombre (#PCDATA)> <!ELEMENT fabricante (#PCDATA)> <!ATTLIST fabricante pais CDATA #REQUIRED>
Almacén de repuestos¶
Una empresa de repuestos desea almacenar en XML la información de su inventario:
El elemento raíz debe ser «repuestos»
Dentro de «repuestos» debe haber uno o más «repuesto».
- Dentro de «repuesto» debe haber una de estas dos cosas: «tornillo» o «tuerca»
3.1 Tornillo: lleva siempre un atributo «peso». Lleva dentro un elemento llamado «descripcion» 3.2 Tuerca: puede llevar un atributo «peso». Lleva dentro siempre un elemento llamado «material»
Ejemplo de fichero válido
<repuestos>
<repuesto>
<tornillo peso="5g">
<descripcion>Tornillo para ensamblajes metálicos</descripcion>
</tornillo>
</repuesto>
<repuesto>
<tuerca>
<material>Acero</material>
</tuerca>
</repuesto>
<repuesto>
<tuerca peso="12 mg">
<material>Aleación</material>
</tuerca>
</repuesto>
</repuestos>
Y una posible solución:
<!ELEMENT repuestos (repuesto+)>
<!ELEMENT repuesto (tornillo|tuerca)>
<!ELEMENT tornillo (descripcion)>
<!ELEMENT descripcion (#PCDATA)>
<!ELEMENT tuerca (material)>
<!ELEMENT material (#PCDATA)>
<!ATTLIST tornillo peso CDATA #REQUIRED>
<!ATTLIST tuerca peso CDATA #IMPLIED>
Suministros médicos (DTD)¶
En un centro médico se desea almacenar la información sobre el inventario usando XML. Se ha llegado a un acuerdo para almacenar la información en este formato
El elemento raíz se llama «suministrosmedicos». Dentro de él hay lo siguiente:
1.1 Primero hay uno o muchos elementos «antibiotico». Todo antibiotico lleva dentro un elemento «nombre». Puede llevar o no un elemento llamado «nombrecomercial». 1.2 Despues hay uno o muchos elementos «analgesico». El analgesico puede llevar dentro o no un elemento «fechadecaducidad» y despues siempre un elemento nombre. El analgesico siempre lleva un atributo llamado «pvp». 1.3 Despues puede haber 0 o muchos elementos «antitusivo». Todo antitusivo lleva dentro dos elementos QUE PUEDEN IR EN CUALQUIER ORDEN: elemento «tiporeceta» y el elemento «presentacion». La presentacion siempre lleva un atributo «dosisrecomendada»
A continuación se da un ejemplo de fichero:
<suministrosmedicos>
<antibiotico>
<nombre>Penicilina</nombre>
</antibiotico>
<antibiotico>
<nombre>Penicilina</nombre>
<nombrecomercial>Zitromax</nombrecomercial>
</antibiotico>
<antibiotico>
<nombre>Amoxicilina</nombre>
</antibiotico>
<analgesico pvp="14.80 euros">
<nombre>Paracetamol</nombre>
</analgesico>
<analgesico pvp="14.80 euros">
<fechadecaducidad>15-02-2026</fechadecaducidad>
<nombre>Apiretal</nombre>
</analgesico>
<antitusivo>
<tiporeceta>Innecesaria</tiporeceta>
<presentacion dosisrecomendada="1-1-1">Jarabe</presentacion>
</antitusivo>
<antitusivo>
<presentacion dosisrecomendada="1-1-1">Jarabe</presentacion>
<tiporeceta>Atencion primaria</tiporeceta>
</antitusivo>
<antitusivo>
<tiporeceta>Atencion primaria</tiporeceta>
<presentacion dosisrecomendada="0-0-1">Pastillas</presentacion>
</antitusivo>
</suministrosmedicos>
Y una posible solución:
<!ELEMENT suministrosmedicos (antibiotico+, analgesico+, antitusivo*)>
<!ELEMENT antibiotico (nombre, nombrecomercial?)>
<!ELEMENT nombre (#PCDATA)>
<!ELEMENT nombrecomercial (#PCDATA)>
<!ELEMENT analgesico (fechadecaducidad?, nombre)>
<!ELEMENT fechadecaducidad (#PCDATA)>
<!ELEMENT antitusivo ( (tiporeceta,presentacion) | (presentacion,tiporeceta) )>
<!ELEMENT tiporeceta (#PCDATA)>
<!ELEMENT presentacion (#PCDATA)>
<!--Atributos-->
<!ATTLIST analgesico pvp CDATA #REQUIRED>
<!ATTLIST presentacion dosisrecomendada CDATA #REQUIRED>
Nominas (DTD)¶
Ejercicio¶
La Seguridad Social necesita un formato de intercambio unificado para distribuir la información personal de los afiliados.
Todo archivo XML contiene un listado de uno o mas afiliados
Todo afiliado tiene los siguientes elementos:
DNI o NIE
Nombre
Apellidos
Situación laboral: que tiene que ser una y solo una de entre estas posibilidades: «en_paro», «en_activo», «jubilado», «edad_no_laboral»
Fecha de nacimiento: que se desglosa en los elementos obligatorios día, mes y anio.
Listado de bajas: que indica las situaciones de baja laboral del empleado. Dicho listado consta de una repetición de 0 o más bajas:
Una baja consta de tres elementos: causa (obligatoria), fecha de inicio (obligatorio) y fecha de final (optativa),
Listado de prestaciones cobradas: consta de 0 o más elementos prestación, donde se indicará la cantidad percibida (obligatorio), la fecha de inicio (obligatorio) y la fecha de final (obligatorio)
Inventario de piezas (variante)¶
Se desea almacenar nombres de piezas y para ello se ha llegado a este acuerdo:
El elemento raíz se va a llamar «listapiezas».
Dentro de «listapiezas» va a haber uno o muchos elementos «pieza»
Dentro de «pieza» hay tres elementos:
Un elemento llamado «peso» que contiene datos. NO ES OBLIGATORIO QUE ESTÉ
Un elemento llamado «nombre» que contiene datos
Un elemento llamado fabricante que contiene datos.
El fabricante PUEDE LLEVAR un atributo llamado pais que indica el pais.
Ejemplo de fichero válido
<listapiezas>
<pieza>
<!--No hay peso, pero no debe importar, debe darse como bueno-->
<nombre>Pistón</nombre>
<fabricante pais="China"> Asia Electronics</fabricante>
</pieza>
<pieza>
<peso>15</peso>
<nombre>Cilindro</nombre>
<!--No hay atributo pais, pero no debe pasar nada-->
<fabricante>Toyota Motors</fabricante>
</pieza>
</listapiezas>
Ejemplo de fichero que debe dar errores
<listapiezas>
<pieza>
<peso>20</peso>
<nombre>Pistón</nombre>
<!--Aquí falta el fabricante-->
</pieza>
<pieza>
<peso>15</peso>
<!--Aquí falta el nombre-->
<fabricante pais="Japón">Toyota Motors</fabricante>
</pieza>
</listapiezas>
Esquemas XML¶
Los esquemas XML son un mecanismo radicalmente distinto de crear reglas para validar ficheros XML. Se caracterizan por:
Estar escritos en XML. Por lo tanto, las mismas bibliotecas que permiten procesar ficheros XML de datos permitirían procesar ficheros XML de reglas.
Son mucho más potentes: ofrecen soporte a tipos de datos con comprobación de si el contenido de una etiqueta es de tipo
integer
,date
o de otros tipos. También se permite añadir restricciones como indicar valores mínimo y máximo para un número o determinar el patrón que debe seguir una cadena válidaOfrecen la posibilidad de usar espacios de nombres. Los espacios de nombres son similares a los paquetes Java: permiten a personas distintas el definir etiquetas con el mismo nombre pudiendo luego distinguir etiquetas iguales en función del espacio de nombres que importemos.
Un ejemplo¶
Supongamos que deseamos tener ficheros XML con un solo elemento llamado <cantidad>
que debe tener dentro un número.
<cantidad>20</cantidad>
Un posible esquema sería el siguiente:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="cantidad" type="xsd:integer"/>
</xsd:schema>
¿Qué contiene este fichero?
En primer lugar se indica que este fichero va a usar unas etiquetas ya definidas en un espacio de nombres (o XML Namespace, de ahí
xmlns
). Esa definición se hace en el espacio de nombres que aparece en la URL. Nuestro validador no descargará nada, esa URL es oficial y todos los validadores la conocen. Las etiquetas de ese espacio de nombres van a usar un prefijo que en este caso seráxsd
. Nótese que el prefijo puede ser como queramos (podría ser «abcd» o «zztop»), pero la costumbre es usarxsd
.Se indica que habrá un solo elemento y que el tipo de ese elemento es
<xsd:integer>
. Es decir, un entero básico.
Si probamos el fichero de esquema con el fichero de datos que hemos indicado veremos que efectivamente el fichero XML de datos es válido. Sin embargo, si en lugar de una cantidad incluyésemos una cadena, veríamos que el fichero no se validaría
Tipos de datos básicos¶
Podemos usar los siguientes tipos de datos:
xsd:byte
: entero de 8 bits.xsd:short
: entero de 16 bitsxsd:int
: número entero de 32 bits.xsd:long
: entero de 64 bits.xsd:integer
: número entero sin límite de capacidad.xsd:unsignedByte
: entero de 8 bits sin signo.xsd:unsignedShort
: entero de 16 bits sin signo.xsd:unsignedInt
: entero de 32 bits sin signo.xsd:unsignedLong
: entero de 64 bits sin signo.xsd:string
: cadena de caracteres en la que los espacios en blanco se respetan.xsd:normalizedString
: cadena de caracteres en la que los espacios en blanco no se respetan y se reemplazarán secuencias largas de espacios o fines de línea por un solo espacio.xsd:date
: permite almacenar fechas que deben ir obligatoriamente en formato AAAA-MM-DD (4 digitos para el año, seguidos de un guión, seguido de dos dígitos para el mes, seguidos de un guión, seguidos de dos dígitos para el día del mes)xsd:time
: para almacenar horas en formato HH:MM:SS.Cxsd:datetime
: mezcla la fecha y la hora separando ambos campos con una T mayúscula. Esto permitiría almacenar2020-09-22T10:40:22.6
.xsd:duration
. Para indicar períodos. Se debe empezar con «P» y luego indicar el número de años, meses, días, minutos o segundos. Por ejemplo «P1Y4M21DT8H» indica un período de 1 año, 4 meses, 21 días y 8 horas. Se aceptan períodos negativos poniendo -P en lugar de P.xsd:boolean
: acepta solo valores «true» y «false».xsd:anyURI
: acepta URIs.xsd:anyType
: es como la claseObject
en Java. Será el tipo del cual heredaremos cuando no vayamos a usar ningún tipo especial como tipo padre.
La figura siguiente (tomada de la web del W3C) ilustra todos los tipos así como sus relaciones de herencia:
Derivaciones¶
Prácticamente en cualquier esquema XML crearemos tipos nuevos (por establecer un símil es como si programásemos clases Java). Todos nuestros tipos tienen que heredar de otros tipos pero a la hora de «heredar» tenemos más posibilidades que en Java (dondo solo tenemos el «extends»). En concreto podemos heredar de 4 formas:
Poniendo restricciones (
restriction
). Consiste en tomar un tipo y crear otro nuevo en el que no se puede poner cualquier valor.Extendiendo un tipo (
extension
). Se toma un tipo y se crea uno nuevo añadiendo cosas a los posibles valores que pueda tomar el tipo inicial.Haciendo listas (
lists
). Es como crear vectores en Java.Juntando otros tipos para crear tipos complejos (
union
). Es como crear clases Java en las que añadimos atributos de tipoint
,String
, etc…
En general, las dos derivaciones más usadas con diferencia son las restricciones y las extensiones, que se comentan por separado en los puntos siguientes.
Tipos simples y complejos¶
Todo elemento de un esquema debe ser de uno de estos dos tipos.
Un elemento es de tipo simple si no permite dentro ni elementos hijo ni atributos.
Un elemento es tipo complejo si permite tener dentro otras cosas (que veremos en seguida). Un tipo complejo puede a su vez tener contenido simple o contenido complejo:
Los que son de contenido simple no permiten tener dentro elementos hijo pero sí permiten atributos.
Los que son de contenido complejo sí permiten tener dentro elementos hijo y atributos.
El diagrama siguiente refleja como funciona la estructuración de tipos de los XML Schema.
Así, por ejemplo un tipo simple que no lleve ninguna restricción se puede indicar con el campo type
de un element
como hacíamos antes:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="cantidad" type="xsd:integer"/>
</xsd:schema>
Sin embargo, si queremos indicar alguna restricción adicional ya no podremos usar el atributo type
. Deberemos reescribir nuestro esquema así:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:simpleType>
Aquí irán las restricciones, que hemos omitido por ahora.
</xsd:simpleType>
</xsd:schema>
Ejercicio:edad de los trabajadores¶
Se desea crear un esquema que permita validar la edad de un trabajador, que debe tener un valor entero de entre 16 y 65.
Por ejemplo, este XML debería validarse:
<edad>28</edad>
Pero este no debería validarse:
<edad>-3</edad>
La solución podría ser algo así:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="edad"
type="tipoEdad"/>
<xsd:simpleType name="tipoEdad">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="16"/>
<xsd:maxInclusive value="65"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: peso de productos¶
Se desea crear un esquema que permita validar un elemento peso, que puede tener un valor de entre 0 y 1000 pero aceptando valores con decimales, como por ejemplo 28.88
Una posible solución sería:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="peso" type="tipoPeso"/>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="1000"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: pagos validados¶
Crear un esquema que permita validar un elemento pago
en el cual puede haber cantidades enteras de entre 0 y 3000 euros.
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="pago" type="tipoPago"/>
<xsd:simpleType name="tipoPago">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="3000"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: validación de DNIs¶
Crear un esquema que permita validar un único elemento dni
que valide el patrón de 7-8 cifras + letra que suelen tener los DNI en España:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="dni" type="tipoDNI"/>
<xsd:simpleType name="tipoDNI">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{7,8}[A-Z]"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Uniendo la herencia y el sistema de tipos¶
Llegados a este punto ocurre lo siguiente:
Por un lado tenemos que especificar si nuestros tipos serán simples o complejos (los cuales a su vez pueden ser complejos con contenido simple o complejos con contenido complejo).
Por otro lado se puede hacer herencia ampliando cosas (extensión) o reduciendo cosas (restricciones a los valores).
Se deduce por tanto que no podemos aplicar todas las «herencias» a todos los tipos:
Los tipos simples no pueden tener atributos ni subelementos, por lo tanto les podremos aplicar restricciones pero nunca la extensión.
Los tipos complejos (independientemente del tipo de contenido) sí pueden tener otras cosas dentro por lo que les podremos aplicar tanto restricciones como extensiones.
Restricciones¶
Como se ha dicho anteriormente la forma más común de trabajar es crear tipos que en unos casos aplicarán modificaciones en los tipos ya sea añadiendo cosas o restringiendo posibilidades. En este apartado se verá como aplicar restricciones.
Si queremos aplicar restricciones para un tipo simple las posibles restricciones son:
minInclusive
para indicar el menor valor numérico permitido.maxInclusive
para indicar el mayor valor numérico permitido.minExclusive
para indicar el menor valor numérico que ya no estaría permitido.maxExclusive
para indicar el mayor valor numérico que ya no estaría permitido.totalDigits
para indicar cuantas posibles cifras se permiten.fractionDigits
para indicar cuantas posibles cifras decimales se permiten.length
para indicar la longitud exacta de una cadena.minLength
para indicar la longitud mínima de una cadena.maxLength
para indicar la longitud máxima de una cadena.enumeration
para indicar los valores aceptados por una cadena.pattern
para indicar la estructura aceptada por una cadena.
Si queremos aplicar restricciones para un tipo complejo con contenido las posibles restricciones son las mismas de antes, pero además podemos añadir el elemento <attribute> así como las siguientes.
sequence
para indicar una secuencia de elementoschoice
para indicar que se debe elegir un elemento de entre los que aparecen.
Atributos¶
En primer lugar es muy importante recordar que si queremos que un elemento tenga atributos entonces ya no se puede considerar que sea de tipo simple. Se debe usar FORZOSAMENTE un complexType. Por otro lado en los XML Schema todos los atributos son siempre opcionales, si queremos hacerlos obligatorios habrá que añadir un «required».
Un atributo se define de la siguiente manera:
<xsd:attribute name="fechanacimiento" type="xsd:date" use="required"/>
Esto define un atributo llamado nombre
que aceptará solo fechas como valores válidos y que además es obligatorio poner siempre.
Ejercicios de XML Schemas¶
Cantidades limitades¶
Crear un esquema que permita verificar algo como lo siguiente:
<cantidad>20</cantidad>
Se necesita que la cantidad tenga solo valores aceptables entre -30 y +30.
Solución a las cantidades limitadas¶
La primera pregunta que debemos hacernos es ¿necesitamos crear un tipo simple o uno complejo?. Dado que nuestro único elemento no tiene subelementos ni atributos dentro podemos afirmar que solo necesitamos un tipo simple.
Como aparentemente nuestro tipo necesita usar solo valores numéricos y además son muy pequeños nos vamos a limitar a usar un short
. Sobre ese short
pondremos una restriccion que permita indicar los valores mínimo y máximo.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="cantidad">
<xs:simpleType>
<xs:restriction base="xs:short">
<xs:minInclusive value="-30"/>
<xs:maxInclusive value="30"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
Este esquema dice que el elemento raíz debe ser cantidad
. Luego indica que es un tipo simple y dentro de él indica que se va a establecer una restricción teniendo en mente que se va a «heredar» del tipo short
. En concreto se van a poner dos restricciones, una que el valor mínimo debe ser -30 y otra que el valor máximo debe ser 30.
Existe una alternativa más recomendable, que es separar los elementos de los tipos. De esa manera, se pueden «reutilizar» las definiciones de tipos.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="cantidad" type="tipoCantidades">
</xs:element>
<xs:simpleType name="tipoCantidades">
<xs:restriction base="xs:short">
<xs:minInclusive value="-30"/>
<xs:maxInclusive value="30"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Obsérvese que hemos puesto el tipo por separado y le hemos dado el nombre tipoCantidades
. El elemento raíz tiene su nombre y su tipo en la misma línea.
Cantidades limitadas con atributo divisa¶
Se desea crear un esquema para validar XML en los que haya un solo elemento raíz llamado cantidad en el que se debe poner siempre un atributo «divisa» que indique en qué moneda está una cierta cantidad. El atributo divisa siempre será una cadena y la cantidad siempre será un tipo numérico que acepte decimales (por ejemplo float
). El esquema debe validar los archivos siguientes:
<cantidad divisa="euro">20</cantidad>
<cantidad divisa="dolar">18.32</cantidad>
Pero no debe validar ninguno de los siguientes:
<cantidad>20</cantidad>
<cantidad divisa="dolar">abc</cantidad>
Solución a las cantidades limitadas con atributo divisa¶
Crearemos un tipo llamado «tipoCantidad». Dicho tipo ya no puede ser un simpleType ya que necesitamos que haya atributos. Como no necesitamos que tenga dentro subelementos entonces este complexType
llevará dentro un simpleContent
(y no un complexContent
).
Aparte de eso, como queremos «ampliar» un elemento para que acepte tener dentro un atributo obligatorio «cantidad» usaremos una <extension>
. Así, el posible esquema sería este:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="cantidad" type="tipoCantidad"/>
<xsd:complexType name="tipoCantidad">
<xsd:simpleContent>
<xsd:extension base="xsd:float">
<xsd:attribute name="divisa" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:schema>
Cantidades limitadas con atributo divisa con solo ciertos valores¶
Queremos ampliar el ejercicio anterior para evitar que ocurran errores como el siguiente:
<cantidad divisa="aaaa">18.32</cantidad>
Vamos a indicar que el atributo solo puede tomar tres posibles valores: «euros», «dolares» y «yenes».
Solución al atributo con solo ciertos valores¶
Ahora tendremos que crear dos tipos. Uno para el elemento cantidad
y otro para el atributo divisa
. Llamaremos a estos tipos tipoCantidad
y tipoDivisa
.
La solución comentada puede encontrarse a continuación. Como puede verse, hemos includo comentarios. Pueden insertarse etiquetas annotation
que permiten incluir anotaciones de diversos tipos, siendo la más interesante la etiqueta documentation
que nos permite incluir comentarios.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="cantidad" type="tipoCantidad"/>
<xsd:annotation>
<xsd:documentation>
A continuación creamos el tipo cantidad
</xsd:documentation>
</xsd:annotation>
<xsd:complexType name="tipoCantidad">
<xsd:annotation>
<xsd:documentation>
Como solo va a llevar atributos debemos
usar un simpleContent
</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:annotation>
<xsd:documentation>
Como queremos "ampliar" un tipo/clase
para que lleve atributos usaremos
una extension
</xsd:documentation>
</xsd:annotation>
<xsd:extension base="xsd:float">
<xsd:attribute name="divisa" type="tipoDivisa"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Ahora tenemos que fabricar el "tipoDivisa" que indica
los posibles valores válidos para una divisa. Estas
posibilidades se crean con una "enumeration". Nuestro
tipo es un "string" y como vamos a restringir los posibles
valores usaremos "restriction"
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType name="tipoDivisa">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="euros"/>
<xsd:enumeration value="dolares"/>
<xsd:enumeration value="yenes"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: codigos y sedes¶
Se necesita tener un esquema que valide un fichero en el que hay un solo elemento llamado codigo
Dentro de código hay una cadena con una estructura rígida: 2 letras mayúsculas, seguidas de 2 cifras, seguidas a su vez de 3 letras.
El elemento
código
debe llevar un atributosede
que será de tipo cadena.
Solución a los códigos y sedes¶
Se nos piden dos cosas:
Restringir un tipo básico, en este caso el
string
Extender una etiqueta para que tenga un atributo.
Como no se puede hacer a la vez, deberemos dar dos pasos. Primero crearemos un tipo con la restricción y despues crearemos un segundo tipo con la extensión.
Cuando haya conflictos, siempre debemos crear primero la restricción y luego la extensión
Así, creamos primero esto:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="codigo" type="tipoCodigoRestringido"/>
<xsd:simpleType name="tipoCodigoRestringido">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}[0-9]{2}[A-Z]{3}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Y despues lo ampliamos para que se convierta en esto:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="codigo" type="tipoCodigo"/>
<xsd:simpleType name="tipoCodigoRestringido">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}[0-9]{2}[A-Z]{3}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoCodigo">
<xsd:simpleContent>
<xsd:extension base="tipoCodigoRestringido">
<xsd:attribute name="sede"
type="xsd:string"
use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:schema>
Ejercicio: productos con atributos¶
Se desea crear un esquema que permita validar un elemento raíz llamado producto
de tipo xsd:string
. El producto tiene dos atributos:
Un atributo se llamará
cantidad
y es obligatorio. Debe aceptar solo enteros positivos.También habrá un atributo llamado
unidad
que solo acepta losxsd:string
«cajas» y «pales».
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="producto" type="tipoProducto"/>
<xsd:complexType name="tipoProducto">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="cantidad"
type="xsd:unsignedInt" use="required"/>
<xsd:attribute name="unidad"
type="tipoUnidad"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tipoUnidad">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="caja"/>
<xsd:enumeration value="pale"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: clientes con información adicional¶
Se desea crear un esquema XML que permita validar un elemento llamado cliente
que puede almacenar un xsd:string
. El cliente contiene:
Un atributo obligatorio llamado
codigo
que contiene el código del cliente, que siempre consta de tres letras mayúsculas de tres números.Un atributo optativo llamado
habitual
que se usará para saber si es un cliente habitual o no. Acepta valores «true» y «false».Un atributo optativo llamado
cantidad
que indica su compra. Es un entero con valores de entre 0 y 1000.
<cliente codigo="AAA222" habitual="true" cantidad="1000">
Pepe Pérez
</cliente>
Lista de clientes como XML Schemas¶
En este apartado volveremos a ver un problema que ya resolvíamos con DTD: supongamos que en nuestros ficheros deseamos indicar que el elemento raíz es <listaclientes>
. Dentro de <listaclientes>
deseamos permitir uno o más elementos <cliente>
. Dentro de <cliente>
todos deberán tener <cif>
y <nombre>
y en ese orden. Dentro de <cliente>
puede aparecer o no un elemento <diasentrega>
para indicar que ese cliente exige un máximo de plazo. Como no todo el mundo usa plazos el <diasentrega>
es optativo.
Vayamos paso a paso. Primero decimos como se llama el elemento raíz y de qué tipo es:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaclientes" type="tipoListaClientes"/>
</xsd:schema>
Ahora queda definir el tipo tipoListaClientes
. Este tipo va a contener un elemento (por lo que ya sabemos que es un complexType
con complexContent
dentro), y en concreto queremos que sea un solo elemento llamado cliente
, es decir queremos imponer una restricción. Aunque queramos un solo elemento tendremos que indicar una restricción. Como queremos permitir que el elemento pueda aparecer muchas veces utilizaremos un maxOccurs
con el valor unbounded
.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaclientes" type="tipoListaClientes"/>
<xsd:complexType name="tipoListaClientes">
<xsd:complexContent>
<xsd:restriction>
<xsd:element name="cliente" type="tipoCliente"
maxOccurs="unbounded"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Definamos ahora el tipo tipoCliente
. Dicho tipo necesita tener subelementos dentro así que evidentemente va a ser de tipo complejo. La pregunta es ¿es «tipo complejo con contenido simple» o «tipo complejo con contenido complejo»?. Si lo hiciéramos de «tipo complejo con contenido simple» podríamos tener atributos pero no subelementos, así que forzosamente tendrá que ser de un «tipo complejo con contenido complejo». Igual que antes impondremos una restricciones que es permitir solo que aparezcan ciertos elementos en cierto orden. El elemento plazo
lo haremos optativo.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaclientes" type="tipoListaClientes"/>
<xsd:complexType name="tipoListaClientes">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="cliente" type="tipoCliente"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoCliente">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="cif" type="xsd:string"/>
<xsd:element name="nombre" type="xsd:string"/>
<xsd:element name="plazo" type="xsd:string"
minOccurs="0"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Si ahora probamos este XML veremos que el fichero se valida perfectamente a pesar de que es evidente que tiene errores. Es lógico, dado que no hemos aprovechado a fondo el sistema de tipos de XML para evitar que nadie suministre datos incorrectos en un XML. Dicha mejora la dejaremos para el siguiente ejercicio.
<listaclientes>
<cliente>
<cif>dd</cif>
<nombre>20</nombre>
</cliente>
<cliente>
<cif>dd</cif>
<nombre>20</nombre>
<plazo>ABCD</plazo>
</cliente>
</listaclientes>
Ampliación del esquema para clientes¶
Ahora ampliaremos el XML Schema del fichero anterior para que nadie suministre información incorrecta.
En concreto tenemos tres datos:
El CIF, que vamos a presuponer que siempre tiene 8 cifras y al final una letra mayúsculas. Si alguna empresa tiene 7 cifras deberá incluir un 0 extra.
El nombre, que puede ser una cadena cualquiera.
El plazo, que debería ser un número positivo válido.
Ahora, el fichero anterior no debería ser validado por el validador, pero sí debería serlo un fichero como este.
<listaclientes>
<cliente>
<cif>01234567D</cif>
<nombre>Juan Sanchez</nombre>
</cliente>
<cliente>
<cif>05676554A</cif>
<nombre>Pedro Diaz</nombre>
<plazo>45</plazo>
</cliente>
</listaclientes>
La solución a los tres problemas indicados antes sería la siguiente:
El nombre puede ser una cadena cualquiera, por lo que tendrá que seguir siendo de tipo
xsd:string
. Eso significa que si alguien introdujese un número en el nombre el fichero seguiría validándose. Por desgracia dicho problema no se puede resolver.El plazo debería ser un número. Le asignaremos un tipo
xsd:unsignedInt
.El CIF es más complejo. Deberemos crear un tipo nuevo y establecer una restricción a los posibles valores que puede tomar.
Así, una posible solución sería esta:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaclientes" type="tipoListaClientes"/>
<xsd:complexType name="tipoListaClientes">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="cliente" type="tipoCliente"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoCliente">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="cif" type="tipoCif"/>
<xsd:element name="nombre" type="xsd:string"/>
<xsd:element name="plazo" type="xsd:unsignedInt" minOccurs="0"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="tipoCif">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{8}[A-Z]"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="tipoPlazo">
<xsd:restriction base="xsd:unsignedInt"/>
</xsd:simpleType>
</xsd:schema>
Ejercicio: lista de códigos¶
Se nos pide crear un esquema que permita validar un fichero como el siguiente:
<listacodigos>
<codigo>AAA2DD</codigo>
<codigo>BBB2EE</codigo>
<codigo>BBB2EE</codigo>
</listacodigos>
En concreto, todo código tiene la estructura siguiente:
Primero van tres mayúsculas
Despues va exactamente un digito.
Por último hay exactamente dos mayúsculas.
Un posible esquema XML sería el siguiente (obsérvese como usamos maxOccurs
para indicar que el elemento puede repetirse un máximo de «infitas veces»:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listacodigos"
type="tipoLista"/>
<xsd:complexType name="tipoLista">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="codigo"
type="tipoCodigo"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="tipoCodigo">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{3}[0-9][A-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: otra lista de clientes¶
Ahora se nos pide crear un esquema que permita validar un fichero como el siguiente, en el que hay una lista de clientes y el nombre es optativo, aunque los apellidos son obligatorios:
<listaclientes>
<cliente>
<nombre>Juan</nombre>
<apellidos>Sanchez</apellidos>
</cliente>
<cliente>
<nombre>Jose</nombre>
<apellidos>Diaz</apellidos>
</cliente>
</listaclientes>
La solución puede ser algo así:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaclientes"
type="tipoLista"/>
<xsd:complexType name="tipoLista">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="cliente"
type="tipoCliente"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoCliente">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="nombre"
type="xsd:string"
minOccurs="0"/>
<xsd:element name="apellidos"
type="xsd:string"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Ejercicio: lista de alumnos¶
Se desea construir un esquema para validar listas de alumnos en las que:
La raíz es
listaalumnos
.Dentro de ella hay uno o más
alumno
. Todoalumno
tiene siempre un atributo DNI que es obligatorio y que tiene una estructura formada por 7 u 8 cifras seguidas de una mayúscula.Todo
alumno
tiene un elementonombre
y unap1
obligatorios.Todo
alumno
puede tener despues delap1
un elementoap2
y unoedad
, ambos son optativos.El elemento
edad
debe ser entero y positivo.
(Gracias a Jesús VB por corregir una errata)
Un ejemplo de fichero:
<listaalumnos>
<!--DNI atributo obligatorio-->
<alumno dni="5667545Z">
<!--Nombre y ap1 obligatorios-->
<nombre>Jose</nombre>
<ap1>Sanchez</ap1>
</alumno>
<alumno dni="5778221D">
<nombre>Andres</nombre>
<ap1>Ruiz</ap1>
<!--Ap2 y edad son optativos-->
<ap2>Ruiz</ap2>
<!--La edad debe ser positiva-->
<edad>25</edad>
</alumno>
</listaalumnos>
Y a continuación una posible solución:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaalumnos" type="tipoListaAlumnos"/>
<xsd:complexType name="tipoListaAlumnos">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="alumno"
type="tipoAlumno"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoAlumno">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="nombre"
type="xsd:string"/>
<xsd:element name="ap1"
type="xsd:string"/>
<xsd:element name="ap2"
type="xsd:string"
minOccurs="0"/>
<xsd:element name="edad"
type="xsd:positiveInteger"
minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="dni" type="tipoDNI" use="required"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="tipoDNI">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{7,8}[A-Z]"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: lista de articulos (con atributos optativos)¶
Supongamos el fichero siguiente con las reglas que se explicitan en los comentarios:
<listaproductos>
<articulo>
<!--Estructura 2 letras,2 cifras-->
<codigo>CD12</codigo>
<!--Descripcion es optativo y su atributo autor tb-->
<descripcion autor="Pepe">Monitor</descripcion>
</articulo>
<articulo>
<codigo>CA12</codigo>
</articulo>
<articulo>
<codigo>AA99</codigo>
<descripcion>Teclado</descripcion>
</articulo>
</listaproductos>
A continuación se muestra una solución con un esquema que valida ficheros como el indicado:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaproductos" type="tipoListaProductos"/>
<xsd:complexType name="tipoListaProductos">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="articulo"
type="tipoArticulo"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType> <!--Fin de listaarticulos-->
<xsd:complexType name="tipoArticulo">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="codigo" type="tipoCodigo"/>
<xsd:element name="descripcion"
type="tipoDescripcion"
minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType> <!--Fin de articulo-->
<xsd:simpleType name="tipoCodigo">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}[0-9]{2}"/>
</xsd:restriction>
</xsd:simpleType> <!--Fin de codigo-->
<xsd:complexType name="tipoDescripcion">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="autor" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:schema>
Ejercicio: lista de componentes (un enfoque distinto)¶
Dado un archivo como el siguiente en el cual aparecen las reglas incluidas como comentarios, crear el esquema que valide la estructura de tales ficheros:
<listacomponentes>
<!--Obligatoria fecha entrega-->
<componente entrega="2018-03-15">
<fabricante>
<!--Posibles fabricantes FAB1, FAB2 y FAB3-->
<nombre>FAB1</nombre>
<!--Calificacion es un string y es optativa-->
<calificacion>Positiva</calificacion>
</fabricante>
<!--Atributo unidad es cadena. Dentro de peso
solo puede haber numeros con decimales y mayores de 0-->
<peso unidad="kg">40.5</peso>
</componente>
<componente entrega="2018-12-31">
<fabricante>
<nombre>FAB2</nombre>
</fabricante>
<peso unidad="miligramos">260.5</peso>
</componente>
</listacomponentes>
Ahora en lugar de ir definiendo tipos empezando por el elemento raíz vamos a ir definiendo primero los tipos de los elementos más básicos que encontremos, e iremos construyendo los tipos más complejos a partir de los tipos fáciles que ya hayamos construido. Como veremos despues, el resultado va a ser el mismo.
La solución:
n<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:simpleType name="tipoNombre">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="FAB1"/>
<xsd:enumeration value="FAB2"/>
<xsd:enumeration value="FAB3"/>
</xsd:restriction>
</xsd:simpleType>
<!--Tipo auxiliar, el atributo lo incluimos despues-->
<xsd:simpleType name="tipoPesoRestringido">
<xsd:restriction base="xsd:float">
<xsd:minExclusive value="0"/>
</xsd:restriction>
</xsd:simpleType>
<!--En este tipo peso incluimos ya el atributo-->
<xsd:complexType name="tipoPeso">
<xsd:simpleContent>
<xsd:extension base="tipoPesoRestringido">
<xsd:attribute name="unidad"
type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="tipoFabricante">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="nombre"
type="tipoNombre"/>
<xsd:element name="calificacion"
type="xsd:string"
minOccurs="0"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoComponente">
<xsd:sequence>
<xsd:element name="fabricante"
type="tipoFabricante"/>
<xsd:element name="peso" type="tipoPeso"/>
</xsd:sequence>
<xsd:attribute name="entrega" type="xsd:date"/>
</xsd:complexType>
<xsd:complexType name="tipoListaComponentes">
<xsd:sequence>
<xsd:element name="componente"
type="tipoComponente"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<!--Aunque el elemento aparezca al final,
no pasa nada-->
<xsd:element name="listacomponentes"
type="tipoListaComponentes"/>
</xsd:schema>
Ejercicio: listas con choice¶
Se pide elaborar un esquema que valide un fichero con las restricciones siguientes:
El elemento raíz es
articulos
. Dicho elemento raíz debe llevar siempre un atributofechaGeneración
.Dentro de la raíz puede haber uno o varios de cualquiera de los siguientes elementos:
monitor
,teclado
oraton
. Cualquiera de los tres elementos puede llevar un atributocodigo
que tiene siempre la estructura «tres letras, guión, tres letras, guión, tres cifras». Además, cualquiera de los tres debe llevar dentro y en primer lugar un elementodescripción
que contiene texto.Un monitor debe llevar (aparte de la descripción que va en primer lugar) un elemento
resolución
que a su vez debe llevar dentro dos elementos y en este ordenancho
yalto
. Tantoancho
, comoalto
deben llevar siempre dentro un entero positivo.Un
ratón
debe llevar (aparte de la descripción que va en primer lugar) un elementopeso
que siempre lleva dentro un entero positivo. Además, elpeso
lleva siempre dentro un atributounidad
que solo puede valer «g» o «cg».
En el fichero siguiente se muestra un ejemplo
<!--Obligatorio el tener fechaGeneracion-->
<articulos fechageneracion="2018-03-01">
<!--El atributo codigo es optativo siempre-->
<monitor codigo="AAA-DDD-222">
<!--Descripcion obligatoria-->
<descripcion>Monitor de x pulgadas...</descripcion>
<resolucion>
<ancho>1920</ancho>
<alto>1400</alto>
</resolucion>
</monitor>
<raton>
<!--Descripcion obligatoria-->
<descripcion>Raton ergonomico...</descripcion>
<!--La unidad es g o cg-->
<peso unidad="g">100</peso>
</raton>
<teclado codigo="DDD-XXX-111">
<!---Descripcion obligatoria-->
<descripcion>Teclado estándar</descripcion>
</teclado>
<monitor codigo="CCC-GGG-666">
<!--Descripcion obligatoria-->
<descripcion>Monitor de x pulgadas...</descripcion>
<resolucion>
<ancho>1400</ancho>
<alto>1000</alto>
</resolucion>
</monitor>
</articulos>
Ejercicio: listas de productos¶
Se pide validar correctamente algo como esto:
<listaproductos>
<producto codigo="DX-22"><!--Codigo obligatorio-->
<descripcion>Ordenador</descripcion><!--Optativa-->
<peso>23.44</peso><!--Positivo con decimales-->
</producto>
<producto codigo="CX-124">
<peso>17.50</peso>
</producto>
<producto codigo="CX-124">
<peso>17.50</peso>
</producto>
</listaproductos>
Las reglas son:
Una lista de productos puede tener dentro muchos productos.
Todo producto tiene un «codigo» cuya estructura dos mayúsculas seguidas de un guión seguido de dos o tres cifras
Todo producto puede tener (optativo) un elemento descripción que es de tipo texto.
Todo producto debe tener un elemento peso que debe aceptar decimales pero que nunca puede ser negativo, es decir su valor mínimo es 0
La solución se muestra a continuación:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listaproductos" type="tipoLista"/>
<xsd:complexType name="tipoLista">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="producto"
type="tipoProducto"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoProducto">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="descripcion"
type="xsd:string"
minOccurs="0"/>
<xsd:element name="peso"
type="tipoPeso"/>
</xsd:sequence>
<xsd:attribute name="codigo"
type="tipoCodigo"
use="required"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="tipoCodigo">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}-[0-9]{2,3}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio: validación de componentes¶
Validar un fichero como este:
<listacomponentes>
<componente>
<tarjetagrafica>
<memoria>2GB</memoria>
<precio moneda="euros">190</precio>
</tarjetagrafica>
</componente>
<componente codigo="123456">
<monitor>
<tamanio>14</tamanio>
<precio moneda="euros">99.49</precio>
</monitor>
</componente>
</listacomponentes>
Las reglas son las siguientes:
El elemento raíz se llama
listacomponentes
.Dentro de él puede haber uno o más elementos
componente
Un componente puede ser una
tarjetagrafica
o unmonitor
.Un componente puede tener un atributo llamado
codigo
cuya estructura es siempre un dígito de 6 cifras.Una tarjeta gráfica siempre tiene dos elementos llamados
memoria
yprecio
.La memoria siempre es una cifra seguido de GB o TB.
El tamaño del monitor siempre es un entero positivo.
El precio siempre es una cantidad positiva con decimales. El precio siempre lleva un atributo
moneda
que solo puede valer «euros» o «dolares» y que se utiliza para saber en qué moneda está el precio.
La solución se muestra a continuación:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="listacomponentes" type="tipoLista"/>
<xsd:complexType name="tipoLista">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="componente"
type="tipoComponente"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoComponente">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:choice>
<xsd:element name="tarjetagrafica" type="tipoTarjeta"/>
<xsd:element name="monitor" type="tipoMonitor"/>
</xsd:choice>
<xsd:attribute name="codigo" type="tipoCodigo"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="tipoCodigo">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[1-9][0-9]{5}"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoTarjeta">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="memoria" type="tipoMemoria"/>
<xsd:element name="precio" type="tipoPrecio"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="tipoMemoria">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]+[GT]B"/>
</xsd:restriction>
</xsd:simpleType>
<!--Aqui definimos un precio con restriccion del cual
heredaremos despues para añadir el atributo a
la cantidad-->
<xsd:simpleType name="tipoPrecioRestringido">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
</xsd:restriction>
</xsd:simpleType>
<!--Aqui heredamos del tipo anterior y añadimos
el atributo-->
<xsd:complexType name="tipoPrecio">
<xsd:simpleContent>
<xsd:extension base="tipoPrecioRestringido">
<xsd:attribute name="moneda" type="tipoMoneda"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tipoMoneda">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="euros"/>
<xsd:enumeration value="dolares"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoMonitor">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="tamanio" type="xsd:integer"/>
<xsd:element name="precio" type="tipoPrecio"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Ejercicio: inventario¶
Varios administradores necesitan intercambiar información sobre inventario de material de oficina. Para ello, han llegado a un acuerdo sobre lo que se permite en un fichero XML de inventario. La idea básica es permitir ficheros como este:
<inventario>
<objeto>
<mesa>
<peso>4.55</peso>
<superficie unidad="cm2">100</superficie>
</mesa>
</objeto>
<objeto>
<silla>
<peso>3.50</peso>
</silla>
</objeto>
</inventario>
Las reglas concretas son estas:
Dentro de
<objeto>
puede haber uno de estos dos elementos hijo: un elemento<mesa>
o un elemento<silla>
.Toda mesa tiene un elemento hijo
<peso>
. El peso siempre es un decimal positivo con dos cifras decimales.Toda mesa tiene una
<superficie>
. La superficie es ununsignedInt
. La superficie siempre tiene un atributo que puede ser solo una de estas dos cadenas:m2
ocm2
.Toda silla tiene siempre un
<peso>
y las reglas de ese peso son exactamente las mismas que las reglas de<peso>
del elemento<mesa>
La solución podría descomponerse de la forma siguiente:
Resolvamos primero el problema de crear un tipo para el elemento <peso>
.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="peso"
type="tipoPeso"></xsd:element>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ahora resolvamos el problema del elemento <silla>
. Para resolverlo, podemos aprovechar el tipo tipoPeso
que acabamos de crear:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="silla"
type="tipoSilla"></xsd:element>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoSilla">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="peso"
type="tipoPeso"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Ahora resolveremos el problema de la superficie:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="superficie"
type="tipoSuperficie"></xsd:element>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoSilla">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="peso"
type="tipoPeso"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoSuperficie">
<xsd:simpleContent>
<xsd:extension base="xsd:unsignedInt">
<xsd:attribute name="unidad"
type="tipoUnidad"
use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tipoUnidad">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="m2"/>
<xsd:enumeration value="cm2"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Y apoyándonos en eso haremos la mesa:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="mesa"
type="tipoMesa"></xsd:element>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoSilla">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="peso"
type="tipoPeso"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoSuperficie">
<xsd:simpleContent>
<xsd:extension base="xsd:unsignedInt">
<xsd:attribute name="unidad"
type="tipoUnidad"
use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tipoUnidad">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="m2"/>
<xsd:enumeration value="cm2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoMesa">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="peso"
type="tipoPeso"/>
<xsd:element name="superficie"
type="tipoSuperficie"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Y ya solo queda indicar que un inventario es una lista de objetos (pondremos el maxOccurs
a unbounded
) e indicaremos que un objeto puede ser una elección (<xsd:choice>
) entre dos tipos de objetos.
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="inventario"
type="tipoInventario"/>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:decimal">
<xsd:minInclusive value="0"/>
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoSilla">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="peso"
type="tipoPeso"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoSuperficie">
<xsd:simpleContent>
<xsd:extension base="xsd:unsignedInt">
<xsd:attribute name="unidad"
type="tipoUnidad"
use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tipoUnidad">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="m2"/>
<xsd:enumeration value="cm2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoMesa">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="peso"
type="tipoPeso"/>
<xsd:element name="superficie"
type="tipoSuperficie"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoInventario">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="objeto"
type="tipoObjeto"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoObjeto">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:choice>
<xsd:element name="mesa" type="tipoMesa"/>
<xsd:element name="silla" type="tipoSilla"/>
</xsd:choice>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:schema>
Ejercicio XML Schemas tipo examen (I)¶
Se necesita crear un esquema que controle la correcta sintaxis de ficheros con este estilo:
<productosfinancieros>
<producto>
<bono>
<valoractual moneda="yenes">2.212</valoractual>
<beneficio>-2.83</beneficio>
</bono>
</producto>
<producto>
<futuro>
<elemento idioma="espanol">Petroleo</elemento>
<beneficio>-3.83</beneficio>
</futuro>
</producto>
<producto>
<acciones>
<empresa pais="usa">ENRON</empresa>
<beneficio>2.91</beneficio>
</acciones>
</producto>
</productosfinancieros>
Las reglas concretas son las siguientes:
El elemento raíz es
<productosfinancieros>
. Dentro de él debe haber uno o más elementos<producto>
.Un
<producto>
puede ser de tres tipos:<bono>
,<futuro>
y<acciones>
.Todos los productos tienen siempre un elemento hijo llamado
<beneficio>
que puede ser un número con dos decimales (puede ser positivo o negativo).Todo
<bono>
puede tener dentro un elemento llamado<valoractual>
que contiene un valor decimal que puede ser positivo o negativo y tener o no decimales. El elemento<valoractual>
deberá llevar dentro un atributo llamadomoneda
que solo puede tomar los valoresdolares
,euros
oyenes
.Todo
<futuro>
tiene un hijo llamado<elemento>
que puede contener dentro cadenas de cualquier tipo. Para saber en qué idioma está la cadena se usa un atributo llamadoidioma
que indica el idioma en el que está escrita la cadena.Las acciones siempre tienen un elemento
<empresa>
que indica el nombre de la empresa y un atributo llamadopaís
que indica de donde es la empresa. De momento queremos limitarnos a los paísesusa
,alemania
,japon
yespana
.
Recuérdese que siempre que no nos digan nada, se supone que un elemento o atributo es obligatorio. Si algo es optativo nos dirán «puede tener dentro», «puede contener», «puede aparecer», etc…
Una posible solución sería esta:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="productosfinancieros"
type="tipoProductosFinancieros"/>
<xsd:complexType name="tipoProductosFinancieros">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="producto"
type="tipoProducto"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoProducto">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:choice>
<xsd:element name="bono"
type="tipoBono"/>
<xsd:element name="futuro"
type="tipoFuturo"/>
<xsd:element name="acciones"
type="tipoAcciones"/>
</xsd:choice>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoBono">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="valoractual"
type="tipoValorActual"/>
<xsd:element name="beneficio"
type="tipoBeneficio"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoValorActual">
<xsd:simpleContent>
<xsd:extension base="xsd:decimal">
<xsd:attribute name="moneda" type="tipoMoneda"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tipoMoneda">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="dolares"/>
<xsd:enumeration value="euros"/>
<xsd:enumeration value="yenes"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="tipoBeneficio">
<xsd:restriction base="xsd:decimal">
<xsd:fractionDigits value="2"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoFuturo">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="elemento"
type="tipoElemento"/>
<xsd:element name="beneficio"
type="tipoBeneficio"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<!--No nos dicen nada sobre los posibles idiomas,
así que podemos asumir que el idioma será una cadena cualquiera-->
<xsd:complexType name="tipoElemento">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="idioma"
type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="tipoAcciones">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="empresa"
type="tipoEmpresa"/>
<xsd:element name="beneficio"
type="tipoBeneficio"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoEmpresa">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="pais"
type="tipoPais"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tipoPais">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="alemania"/>
<xsd:enumeration value="japon"/>
<xsd:enumeration value="espania"/>
<xsd:enumeration value="usa"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio XML Schemas tipo examen (II)¶
Crear una DTD que permita validar un fichero como el siguiente:
<inventario>
<objeto codigo="MM2809">
<mesa>
<tipo>Oficina</tipo>
<localizacion>B09</localizacion>
</mesa>
</objeto>
<objeto>
<ordenador>
<procesador fabricante="Intel">
i3
</procesador>
<memoria unidad="GB">2</memoria>
<discoduro>520</discoduro>
</ordenador>
</objeto>
</inventario>
Las reglas son las siguientes:
El elemento raíz es
<inventario>
.Dentro de
<inventario>
debe haber un elemento<objeto>
que lleva dentro una<mesa>
o un<ordenador>
. Todo<objeto>
puede llevar un código que consta de dos letras y cuatro dígitos. Las letras podrían ser tanto mayúsculas como minúsculas.Dentro de mesa puede haber (o no) un primer elemento
<tipo>
. Despues debe haber un elemento<localizacion>
.Dentro de ordenador puede haber 3 elementos optativos pero que de aparecer lo hacen en el siguiente orden.
Primero un elemento
<procesador>
que puede llevar un atributofabricante
.Despues un elemento
<memoria>
que debe llevar obligatoriamente un atributounidad
.Despues un elemento
<discoduro>
.
Una posible solución sería esta:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="inventario" type="tipoInventario"/>
<xs:complexType name="tipoInventario">
<xs:sequence>
<xs:element name="objeto"
type="tipoObjeto" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType> <!--Fin del tipoInventario-->
<xs:complexType name="tipoObjeto">
<xs:choice>
<xs:element name="mesa" type="tipoMesa"/>
<xs:element name="ordenador" type="tipoOrdenador"/>
</xs:choice>
<xs:attribute name="codigo" type="tipoCodigo"/>
</xs:complexType>
<xs:complexType name="tipoMesa">
<xs:sequence>
<xs:element name="tipo" type="xs:string" minOccurs="0"/>
<xs:element name="localizacion" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="tipoCodigo">
<xs:restriction base="xs:string">
<xs:pattern value="[a-zA-Z]{2}[0-9]{4}"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="tipoOrdenador">
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:sequence>
<xs:element name="procesador"
type="tipoProcesador"
minOccurs="0"/>
<xs:element name="memoria"
type="tipoMemoria"
minOccurs="0"/>
<xs:element name="discoduro" type="xs:nonNegativeInteger"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="tipoProcesador">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="fabricante" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="tipoMemoria">
<xs:simpleContent>
<xs:extension base="xs:float">
<xs:attribute name="unidad" type="xs:string" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
Ejercicio XML Schemas tipo examen (III)¶
Un distribuidor de alimentación necesita un fichero XML que almacene la información sobre pedidos recibidos y entregados que esté regido por un esquema XML que contemple las restricciones siguientes:
El elemento raíz se llama
portes
.Dentro de
portes
, puede haber uno o más de los elementosrecepcion
yentrega
. Su orden puede ser aleatorio y el número de repeticiones también.Un
recepcion
lleva dentro tres elementos: un elementoproducto
, un elementocantidad
y un elementocodigoreceptor
.El
producto
es obligatorio y lleva dentro texto.El elemento
cantidad
(obligatorio) lleva dentro un número con decimales pero que debe ser siempre positivo.El
codigoreceptor
lleva dentro un texto con la estructura: 3 cifras, guión, 3 letras (mayúsculas o minúsculas). Este elementocodigoreceptor
es optativo.Una
entrega
tiene siempre un atributoreceptor
que lleva dentro un texto. Aparte de eso, unaentrega
tiene siempre un elementotransportista
que solo puede valerT1
,T2
oT3
. Despues de el elementotransportista
hay siempre un elementodistancia
. Ladistancia
es un numero mayor de 0. Es necesario que ladistancia
tenga un atributounidad
que indica la unidad en forma de cadena. Además unaentrega
lleva un atributocoste
que siempre es un entero mayor de 0.
A continuación se muestra un fichero de ejemplo
<portes>
<recepcion>
<producto>Fruta</producto>
<cantidad>125.5</cantidad>
<codigoreceptor>333-AZT</codigoreceptor>
</recepcion>
<entrega receptor="Mercados SL" coste="1321">
<transportista>T2</transportista>
<distancia unidad="millas">468</distancia>
</entrega>
<recepcion>
<producto>Verdura</producto>
<cantidad>250</cantidad>
<!--El codigo de receptor no se usó aquí-->
</recepcion>
</portes>
Una posible solución sería esta:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="portes" type="tipoPortes"/>
<xs:complexType name="tipoPortes">
<xs:choice maxOccurs="unbounded">
<xs:element name="recepcion"
type="tipoRecepcion"/>
<xs:element name="entrega"
type="tipoEntrega"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="tipoRecepcion">
<xs:sequence>
<xs:element name="producto" type="xs:string"/>
<xs:element name="cantidad" type="tipoCantidad"/>
<xs:element name="codigoreceptor"
type="tipoCodigoReceptor"
minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="tipoCantidad">
<xs:restriction base="xs:float">
<xs:minInclusive value="0.01"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="tipoCodigoReceptor">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{3}-[A-Za-z]{3}"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="tipoEntrega">
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:sequence>
<xs:element name="transportista"
type="tipoTransportista"/>
<xs:element name="distancia"
type="tipoDistancia"/>
</xs:sequence>
<xs:attribute name="receptor"
type="xs:string"
use="required"/>
<xs:attribute name="coste"
type="xs:nonNegativeInteger"
use="required"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="tipoDistancia">
<xs:simpleContent>
<xs:extension base="xs:nonNegativeInteger">
<xs:attribute name="unidad"
type="xs:string"
use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="tipoTransportista">
<xs:restriction base="xs:string">
<xs:enumeration value="T1"/>
<xs:enumeration value="T2"/>
<xs:enumeration value="T3"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
Ejercicio XML Schemas tipo examen (IV)¶
Se propone el siguiente archivo de datos para una biblioteca:
<!--Dentro de inventario hay uno o muchos libros-->
<inventario>
<!--Dentro de libro, SIEMPRE hay un elemento
titulo y un elemento autor-->
<libro>
<!--Todos los titulos tienen un atributo idioma-->
<titulo idioma="ES">Don Quijote de la Mancha</titulo>
<autor>Miguel de Cervantes</autor>
</libro>
<libro>
<titulo idioma="EN">Hamlet</titulo>
<autor>William Shakespeare</autor>
</libro>
</inventario>
Se desea un XML Schema que pueda hacer cumplir estas reglas. Una posible solución sería esta.
<!--Solución-->
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="inventario"
type="tipoInventario"/>
<xsd:complexType name="tipoInventario">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="libro"
type="tipoLibro"
minOccurs="1"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoLibro">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="titulo"
type="tipoTitulo"/>
<xsd:element name="autor"
type="xsd:string"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoTitulo">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="idioma"
type="xsd:string"
use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:schema>
Ejercicio XML Schemas tipo examen (V)¶
Se propone el siguiente fichero para el inventario de una empresa.
<!--Dentro de listaarticulos hay entre 2 y 6 articulos-->
<listaarticulos>
<!--Todo articulo lleva un código, a veces una descripción
y siempre un peso-->
<articulo>
<!--El código siempre es 3 cifras y dos minúsculas-->
<codigo>719cf</codigo>
<!--La descripción siempre lleva un atributo
idioma que solo puede ser ES, EN o FR-->
<descripcion idioma="ES">Libro electrónico</descripcion>
<!--El peso siempre está entre 50 y 1500-->
<peso>640</peso>
</articulo>
<articulo>
<codigo>904ps</codigo>
<peso>1499</peso>
</articulo>
</listaarticulos>
Una posible solución sería esta:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<!--Recordad que este elemento
lo ponemos siempre con "autocierre"
por brevedad-->
<xsd:element name="listaarticulos"
type="tipoListaArticulos"/>
<!--Esto explica como funciona el elemento
"listaarticulos"-->
<xsd:complexType name="tipoListaArticulos">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="articulo"
type="tipoArticulo"
minOccurs="2"
maxOccurs="7"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<!--Esto explica como funciona
la etiqueta "articulo"-->
<xsd:complexType name="tipoArticulo">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="codigo"
type="tipoCodigo"/>
<xsd:element name="descripcion"
type="tipoDescripcion"
minOccurs="0"/>
<xsd:element name="peso"
type="tipoPeso"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<!--Esto explica como funciona la
etiqueta "codigo"-->
<xsd:simpleType name="tipoCodigo">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]{3}[a-z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
<!--Desarrollamos el funcionamiento de la
etiqueta "descripcion"-->
<xsd:complexType name="tipoDescripcion">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="idioma"
type="tipoIdioma"
use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<!--Esto desarrolla el idioma de la descripción-->
<xsd:simpleType name="tipoIdioma">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="ES"/>
<xsd:enumeration value="FR"/>
<xsd:enumeration value="EN"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="tipoPeso">
<xsd:restriction base="xsd:float">
<xsd:minInclusive value="50"/>
<xsd:maxInclusive value="1500"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
Ejercicio XML Schemas tipo examen (V)¶
Un puerto necesita controlar las entradas y salidas de los muelles y para ello va a usar un fichero XML con unas reglas como estas.
<!--El elemento raíz es movimientos y siempre lleva un atributo
fecha-->
<movimientos fecha="2022-03-01">
<!--Dentro de movimiento hay infinitos elementos "entrada" o
"salida" que pueden repetirse y/o ir en cualquier orden-->
<entrada>
<!--El codigo de barco siempre lleva un atributo "país"
que contiene cadenas. El codigo de barco siempre es
una B seguida un número de entre 4 y 6 cifras-->
<codigobarco país="Panamá">B0143</codigobarco>
<!--Siempre hay un elemento origen que acepta cadenas-->
<origen>Atenas</origen>
<!--Puede haber 0 o muchos elementos "pasa_por" y que
lleva dentro cadenas-->
<pasa_por>Algeciras</pasa_por>
<pasa_por>Oporto</pasa_por>
<!--Siempre hay un destino que lleva dentro cadenas-->
<destino>Amberes</destino>
</entrada>
<!--La salida siempre lleva un codigo que puede ser "01",
"49" o "DESC"-->
<salida codigo="01">
<codigobarco>B0143</codigobarco>
<!--Puede llevar o no un elemento VACÍO llamado
"tasaspagadas"-->
<tasaspagadas/>
</salida>
</movimientos>
Una posible solución sería esta:
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="movimientos" type="tipoMovimientos"/>
<xsd:complexType name="tipoMovimientos">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:choice maxOccurs="unbounded">
<xsd:element name="entrada"
type="tipoEntrada"/>
<xsd:element name="salida"
type="tipoSalida"/>
</xsd:choice>
<xsd:attribute name="fecha" type="xsd:date"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="tipoSalida">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="codigobarco"
type="tipoCodigoBarco"/>
<xsd:element name="tasaspagadas"
type="tipoVacio"/>
</xsd:sequence>
<xsd:attribute name="codigo" type="tipoCodigo"
use="required"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<xsd:simpleType name="tipoCodigo">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="01"/>
<xsd:enumeration value="49"/>
<xsd:enumeration value="DESC"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="tipoVacio">
<xsd:restriction base="xsd:string">
<xsd:length value="0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="tipoEntrada">
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:sequence>
<xsd:element name="codigobarco"
type="tipoCodigoBarco"/>
<xsd:element name="origen" type="xsd:string"/>
<xsd:element name="pasa_por"
type="xsd:string"
minOccurs="0"
maxOccurs="unbounded"/>
<xsd:element name="destino" type="xsd:string"/>
</xsd:sequence>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
<!-- Explicamos como es la cadena B1040 -->
<xsd:simpleType name="tipoCadenaBarco">
<xsd:restriction base="xsd:string">
<xsd:pattern value="B[0-9]{4,6}"></xsd:pattern>
</xsd:restriction>
</xsd:simpleType>
<!--Y ahora heredamos de ella y le añadimos el atributo-->
<xsd:complexType name="tipoCodigoBarco">
<xsd:simpleContent>
<xsd:extension base="tipoCadenaBarco">
<xsd:attribute name="pais" type="xsd:string"
use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:schema>
Ejercicio XML Schemas tipo examen (VI)¶
Se desea construir un esquema para verificar ficheros como el siguiente. Las reglas que se supone deben cumplir los datos se han adjuntado como comentarios en el propio fichero:
<!--Construir un XML Schema que controle que los ficheros de datos
de un administrador de redes verifiquen esta estructura-->
<nodos>
<!--Puede aparecer cualquiera de estos hijos en cualquier orden
y repetido las veces que sea necesario-->
<router>
<!--Un router PUEDE tener una dirección IP
que tiene la estructura típica de una IP-->
<direccionip>192.168.1.10</direccionip>
<!--Despues de la dirección IP viene solo uno de estos
dos elementos <gestionado/> o <nogestionado/>-->
<gestionado/>
</router>
<!--Toda impresora lleva un modelo que solo puede ser "laser",
"tinta" o "termica".-->
<!--Dentro solo puede haber HP, Epson o Kyocera-->
<impresora modelo="laser">Epson</impresora>
<ordenador>
<!--Todo ordenador lleva un elemento
sistema operativo que solo puede ser
Windows, MacOS o Linux. Siempre hay
un atributo "fechainstalacion" que
indica la fecha-->
<sistemaoperativo fechainstalacion="2022-01-02">Windows</sistemaoperativo>
</ordenador>
</nodos>