Artículo
|
Apuntes de XML |
Restringir documentos XML
¿Por qué restringir los datos?
- La primera razón es que podemos realizar comprobaciones estrictas sobre los datos, para asegurarnos de que tienen un formato válido de acuerdo a lo que queremos.
- Otra razón es la documentación: no siempre estará claro para cualquier persona el significado de un determinado documento XML:
<?xml version="1.0"?> <pagina> <pantalla> <nombre>Compras</nombre> <color>#CC9900</color> <fuente>Arial</fuente> </pantalla> <contenido> <p>Aqui un monton de contenido</p> </contenido> </pagina> <?xml version="1.0"?> <pagina> <pantalla> <nombre>Compras</nombre> <color>#CC9900</color> <fuente>Arial</fuente> </pantalla> <pantalla> <nombre>Mensajes</nombre> <color>#9900FF</color> <fuente>Arial</fuente> </pantalla> <pantalla> <nombre>Noticias</nombre> <color>#EECCEE</color> <fuente>Helvetica</fuente> </pantalla> <contenido> <p>Aqui un monton de contenido</p> </contenido> </pagina> - Viendo el primer ejemplo podemos pensar en que describe información de una pantalla para determinado cliente. Viendo el segundo, la interpretación cambia. En realidad, son varios enlaces a las pantallas disponibles.
- Las DTDs y los esquemas XML aclaran situaciones de este tipo.
- Otra ventaja de los mecanismos de restricción es que no hay que cambiar el código de las aplicaciones si las restricciones cambian (sólo las DTDs o esquemas que sean).
- Como desventaja, la validación supone tiempo adicional de proceso. Una solución posible para algunos sistemas es validar en la fase de desarrollo y pruebas y quitar la validación al implantar el sistema.
DTD's
Un ejemplo de DTD
- Para utilizar una DTD como mecanismo de restricción, se especifica lo siguiente en el documento XML:
<!DOCTYPE Libro SYSTEM "libro.dtd">
- DTD para el ejemplo del libro:
<!ELEMENT Libro (Titulo, Catalogo:Seccion, Catalogo:SubSeccion, Contenido, Compra, Copyright)> <!ATTLIST Libro xmlns CDATA #REQUIRED xmlns:Catalogo CDATA #REQUIRED > <!ELEMENT Titulo (#PCDATA)> <!ELEMENT Catalogo:Seccion (#PCDATA)> <!ELEMENT Catalogo:SubSeccion (#PCDATA)> <!ELEMENT Contenido ((Capitulo+)|(Capitulo+, Separacion?)+)> <!ELEMENT Capitulo (Tema, Seccion+)> <!ATTLIST Capitulo materia (XML|Java) "Java" > <!ELEMENT Tema (#PCDATA)> <!ELEMENT Seccion (#PCDATA)> <!ATTLIST Seccion apartados CDATA #REQUIRED dificil (si|no) "no" > <!ELEMENT Separacion EMPTY> <!ELEMENT Compra (#PCDATA)> <!ELEMENT Copyright (#PCDATA)> <!ENTITY OReillyCopyright SYSTEM "copyright.txt">
Elementos
- Los elementos permitidos se especifican con ELEMENT, seguido del nombre y el tipo del elemento.
- Los elementos que se pueden anidar dentro de otros se especifican entre paréntesis y separados por comas. Importa el orden.
- El tipo menos restrictivo es ANY, que permite cualquier contenido para un elemento.
- Para datos de tipo texto, se usa #PCDATA.
- Para elementos vacíos, EMPTY.
- Modificadores de número de ocurrencias:
- ?: Una vez o ninguna
- +: Al menos una vez
- *: Cualquier número de veces o ninguna
- (nada): Exactamente una vez
- Para opciones alternativas: separar con |.
Atributos
- Los atributos permitidos para un elemento se especifican con ATTLIST y el nombre del elemento seguido de los nombres de los atributos, con un tipo y modificador obligatorios.
- El tipo del atributo puede ser CDATA para cualquier valor, o una enumeración de los valores permitidos.
- Otros posibles tipos son:
- NMTOKEN para restringir el valor a un nombre XML válido (es decir, que empiece con una letra o guión de subrayado y contenga sólo letras, números, guiones de subrayado, guiones y puntos, sin espacios)
- ID, además de las restricciones que impone NMTOKEN, impone que el valor sea único en todo el documento.
- El modificador puede ser #REQUIRED para atributos obligatorios, #IMPLIED para opcionales, o #FIXED valor_fijo para valores fijos. También puede ser un valor por defecto.
Declaración DOCTYPE
- SYSTEM sirve para DTDs "personales". Se puede espicificar un fichero local o un fichero accesible a través de una URL.
- Se puede especificar una DTD pública con PUBLIC, en la que queda reflejado el propietario de la misma, una descripción y el idioma.
<!DOCTYPE elem_raiz PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> - Es posible incrustar la DTD internamente en el documento XML:
<!DOCTYPE elem_raiz [ ... ]>
- Incluso es posible tener una DTD interna y otra externa. En caso de conflictos, prevalece siempre la interna.
Entidades
- En la DTD también se especifica cómo resolver las entidades generales, con ENTITY. Se puede especificar:
- Directamente el contenido entre comillas.
- El contenido de un fichero con SYSTEM.
- En el documento XML se invocan con &...;
- También son útiles las entidades paramétricas, que a diferencia de las generales se utilizan más adelante en la misma DTD en que se definen. Se invocan con %...;
<!ENTITY % Shape "(rect|circle|poly|default)">
Esquemas XML
Esquemas XML vs DTDs
- Ventajas sobre las DTDs:
- Restricciones más precisas sobre los documentos XML (tanto en estructura como en tipos de datos).
- Son documentos XML, por lo que la sintaxis es familiar y las herramientas los pueden manejar sin técnicas especiales (no como las DTDs).
- Soporte para espacios de nombres.
- Permiten definir elementos globales y locales (las DTDs sólo globales).
- Desventajas sobre las DTDs:
- Más complejos. Esto causa:
- Dificultades en su comprensión por humanos, sobre todo si están acostumbrados a las DTDs.
- Herramientas más grandes y lentas.
- Muchas aplicaciones funcionan ya sobre DTDs existentes (la conversión es posible pero llevará un tiempo).
- Se trata de una especificación muy reciente, por lo que el soporte por parte de muchas herramientas aún está en proceso.
- Más complejos. Esto causa:
Un primer ejemplo
- Pasemos a esquema XML esta sencilla DTD:
<!ELEMENT Libreria (Libro)+> <!ELEMENT Libro (Titulo, Autor+, Fecha, ISBN)> <!ELEMENT Titulo (#PCDATA)> <!ELEMENT Autor (#PCDATA)> <!ELEMENT Fecha (#PCDATA)> <!ELEMENT ISBN (#PCDATA)>
- Un esquema XML equivalente:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.libros.org" xmlns="http://www.libros.org" elementFormDefault="qualified"> <xs:element name="Libreria" type="TipoLibreria"/> <xs:complexType name="TipoLibreria"> <xs:sequence> <xs:element name="Libro" type="TipoLibro" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="TipoLibro"> <xs:sequence> <xs:element name="Titulo" type="xs:string"/> <xs:element name="Autor" type="xs:string" maxOccurs="3"/> <xs:element name="Fecha" type="xs:string"/> <xs:element name="ISBN" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:schema>
Características
- Observar que, a diferencia de la DTD, es XML.
- Observar cómo los elementos más generales referencian a los más concretos, hasta llegar a los más básicos. No es la única forma de hacerlo.
- minOccurs y maxOccurs por defecto valen 1.
- Observar cómo definimos los elementos básicos como de tipo string.
- Los elementos vacíos se definen con un complexType sin elementos.
Espacios de nombres
- Hay múltiples espacios de nombres involucrados en un esquema:
- Para los elementos del propio esquema (xmlns:xs).
- Para los elementos a restringir (targetNamespace).
- Para los elementos referenciados con el atributo ref (xmlns), se verá un ejemplo al final.
- El atributo elementFormDefault sirve para exigir que al usar el esquema desde un documento los elementos se asocien con el targetNamespace del esquema.
Uso desde un documento
- Este es un pequeño documento XML que utiliza el esquema:
<?xml version="1.0"?> <Libreria xmlns="http://www.libros.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.libros.org libreria.xsd"> <Libro> <Titulo>My Life and Times</Titulo> <Autor>Paul McCartney</Autor> <Autor>Phil McCartney</Autor> <Fecha>July, 1998</Fecha> <ISBN>94303-12021-43892</ISBN> </Libro> ... </Libreria>
Más estructuras
- Otras posibilidades de estructura, además de sequence:
- choice: Para alternativas.
- all: Para conjuntos de elementos en los que no importa el orden.
- Las tres estructuras pueden tener maxOccurs (en all el máximo es 1) y minOccurs
Tipos
- En un esquema XML se pueden utilizar tipos para los elementos y atributos, de forma similar a cualquier lenguaje de programación.
- Existen una serie de tipos predefinidos, algunos ejemplos:
- string
- boolean (true-false)
- integer
- positiveInteger (desde 1)
- decimal (7.08)
- time (hh:mm:ss)
- date (YYYY-MM-DD)
- anyURI (http://www.web.com)
- ID y NMTOKEN (ver DTDs)
- Es posible crear nuevos tipos de datos a partir de los existentes, imponiendo restricciones a éstos:
<xs:simpleType name="TipoColores"> <xs:restriction base="xs:string"> <xs:enumeration value="rojo"/> <xs:enumeration value="blanco"/> <xs:enumeration value="azul"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="TipoEdad"> <xs:restriction base="xs:integer"> <xs:minInclusive value="18"/> <xs:maxInclusive value="65"/> </xs:restriction> </xs:simpleType> - enumeration, minInclusive y maxInclusive son algunos ejemplos de facetas, hay muchas más.
Atributos
- Veamos cómo se tratan los atributos de los elementos. Dado el siguiente fragmento de DTD:
<!ELEMENT Libro (Titulo, Autor+, Fecha, ISBN)> <!ATTLIST Libro Categoria (biografia | ensayo | ficcion) #REQUIRED Disponible (true | false) "false" Corrector CDATA "" >
- Resulta el siguiente fragmento de esquema XML:
<xs:complexType name="TipoLibro"> <xs:sequence> <xs:element name="Titulo" type="xs:string"/> <xs:element name="Autor" type="xs:string" maxOccurs="3"/> <xs:element name="Fecha" type="xs:string"/> <xs:element name="ISBN" type="xs:string"/> </xs:sequence> <xs:attribute name="categoria" type="TipoCat" use="required"/> <xs:attribute name="disponible" type="xs:boolean" default="false"/> <xs:attribute name="corrector" type="xs:string" default=""/> </xs:complexType> <xs:simpleType name="TipoCat"> <xs:restriction base="xs:string"> <xs:enumeration value="biografia"/> <xs:enumeration value="ensayo"/> <xs:enumeration value="ficcion"/> </xs:restriction> </xs:simpleType> - Si un elemento tiene contenido simple y atributos (por ejemplo: <elem atr=h4>678</elem>), se restringe así:
<xs:element name="elem"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:integer"> <xs:attribute name="atr" type="xs:string" use="required"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element>
Importar esquemas
- Cuando se deben restringir varios espacios de nombre, cada espacio se restringe en un esquema, y desde el principal se importan los demás:
<xs:import schemaLocation="------.xsd"/>
Un ejemplo completo
- Para terminar, un ejemplo completo de un esquema XML:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.miempresa.org/pedidos" xmlns="http://www.miempresa.org/pedidos" elementFormDefault="qualified"> <xs:element name="Pedido" type="TipoPedido"/> <xs:complexType name="TipoPedido"> <xs:sequence> <xs:element name="Destino" type="TipoDireccion"/> <xs:element name="Ordenante" type="TipoDireccion"/> <xs:element name="Observaciones" type="xs:string" minOccurs="0"/> <xs:element name="Contenido" type="TipoContenido"/> </xs:sequence> <xs:attribute name="fecha" type="xs:date" use="required"/> </xs:complexType> <xs:complexType name="TipoDireccion"> <xs:sequence> <xs:element name="Nombre" type="xs:string"/> <xs:element name="Direccion" type="xs:string"/> <xs:element name="Ciudad" type="xs:string"/> <xs:element name="CodPostal" type="TipoCodPostal"/> </xs:sequence> </xs:complexType> <xs:simpleType name="TipoCodPostal"> <xs:restriction base="xs:positiveInteger"> <xs:minInclusive value="1000"/> <xs:maxInclusive value="60000"/> </xs:restriction> </xs:simpleType> <xs:complexType name="TipoContenido"> <xs:sequence> <xs:element name="Producto" type="TipoProducto" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="TipoProducto"> <xs:sequence> <xs:element name="Nombre" type="xs:string"/> <xs:element name="Cantidad" type="TipoCantidad"/> <xs:element name="Precio" type="xs:decimal"/> <xs:element name="Observaciones" type="xs:string" minOccurs="0"/> </xs:sequence> <xs:attribute name="codigo" type="TipoCodigo" use="required"/> </xs:complexType> <xs:simpleType name="TipoCantidad"> <xs:restriction base="xs:positiveInteger"> <xs:maxExclusive value="100"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="TipoCodigo"> <xs:restriction base="xs:string"> <xs:pattern value="\d{3}-[A-Z]{2}"/> </xs:restriction> </xs:simpleType> </xs:schema> - Y un documento que lo utiliza:
<?xml version="1.0" encoding="ISO-8859-1"?> <Pedido xmlns="http://www.miempresa.org/pedidos" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.miempresa.org/pedidos pedido.xsd" fecha="1999-10-20"> <Destino> <Nombre>Alicia Abad</Nombre> <Direccion>Plaza de la Duquesa 12</Direccion> <Ciudad>Albacete</Ciudad> <CodPostal>05020</CodPostal> </Destino> <Ordenante> <Nombre>Roberto Movilla</Nombre> <Direccion>General Ricardos 56</Direccion> <Ciudad>Madrid</Ciudad> <CodPostal>28055</CodPostal> </Ordenante> <Observaciones>Es urgente, mi cesped está muy alto</Observaciones> <Contenido> <Producto codigo="872-AA"> <Nombre>Cortadora de cesped</Nombre> <Cantidad>1</Cantidad> <Precio>148.95</Precio> <Observaciones>Confirmar que es eléctrica</Observaciones> </Producto> <Producto codigo="926-FH"> <Nombre>Taladradora</Nombre> <Cantidad>3</Cantidad> <Precio>10.98</Precio> </Producto> </Contenido> </Pedido>
Otras formas de construir esquemas XML
- Anidando los elementos:
<?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.libros.org" xmlns="http://www.libros.org"> <xsd:element name="Libreria"> <xsd:complexType> <xsd:sequence> <xsd:element name="Libro" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="Titulo" type="xsd:string"/> <xsd:element name="Autor" type="xsd:string"/> <xsd:element name="Fecha" type="xsd:string"/> <xsd:element name="ISBN" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> - Referenciando a los elementos:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.libros.org" xmlns="http://www.libros.org"> <xs:element name="Libreria"> <xs:complexType> <xs:sequence> <xs:element ref="Libro" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Libro"> <xs:complexType> <xs:sequence> <xs:element ref="Titulo" minOccurs="1" maxOccurs="1"/> <xs:element ref="Autor" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="Fecha" minOccurs="1" maxOccurs="1"/> <xs:element ref="ISBN" minOccurs="1" maxOccurs="1"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Titulo" type="xs:string"/> <xs:element name="Autor" type="xs:string"/> <xs:element name="Fecha" type="xs:string"/> <xs:element name="ISBN" type="xs:string"/> </xs:schema> - En ambos casos se utilizan tipos complejos anónimos (sin nombre).
- Se puede hacer lo mismo con los tipos simples.
Comentarios
Últimas noticias
Últimos artículos
















































