Esquemas XML (IV)

Esta es la última parte sobre esquemas.

DECLARACIONES <ATTRIBUTE>

Para declarar atributos, utilizamos la declaración <attribute>, que es del siguiente tipo:

<attribute name="nombre del atributo" type="tipo global" ref="atributo global" form="qualified o unqualified" use="optional o prohibited o required" default="valor por defecto" fixed="valor fijo">

Hay dos formas de declarar un atributo. A) creando un tipo local o B) usando un tipo global.

A diferencia de los elementos, que pueden tener tipos simples o complejos, los atributos solo pueden ser de tipos simples. Recordemos que los tipos complejos son usados para definir tipos que contienen atributos o elementos y los tipos simples son usados para restringir el contenido a solo texto. Debido a que un atributo puede contener solo texto, es obvio que solo pueden ser de tipos simples.

Se pueden reusar atributos refiriéndonos a atributos globales. No necesitamos especificar un tipo en la referencia a otro atributo, ya que el tipo es incluido en la declaración global (obviamente).

UN EJEMPLO CON ATRIBUTOS

Vamos a añadir al ejemplo de la agenda de contactos un par de atributos.

<?xml version="1.0"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:contactos="http://www.example.com/contactos" targetNamespace="http://www.example.com/contactos" elementFormDefault="qualified"> <element name="contactos"> <complexType> <sequence> <element name="contacto" minOccurs="0" maxOccurs="unbounded"> <complexType> <sequence> <element name="persona" type="contactos:TipoPersona"/> <element name="localización" type="contactos:TipoLocalización"/> <element name="teléfono" type="string"/> <element name="conocidos" type="contactos:TipoConocidos"/> <element name="descripción" type="contactos:TipoDescripción"/> </sequence> </complexType> </element> </sequence> <attribute name="versión" type="string" fixed="1.0"/> <attribute name="fuente" type="string"/> </complexType> </element> <complexType name="TipoPersona"> <group ref="contactos:GrupoPersona"/> </complexType> <group name="GrupoPersona"> <sequence> <element name="nombre" type="string" minOccurs="1" maxOccurs="unbounded"/> <element name="apellido1" type="string" minOccurs="0" maxOccurs="1"/> <element name="apellido2" type="string"/> </sequence> </group> <complexType name="TipoLocalización"> <choice minOccurs="0" maxOccurs="unbounded"> <element name="dirección" type="string"/> <sequence> <element name="latitud" type="string"/> <element name="longitud" type="string"/> </sequence> </choice> </complexType> <complexType name="TipoConocidos"> </complexType> <complexType name="TipoDescripción" mixed="true"> <choice minOccurs="0" maxOccurs="unbounded"> <element name="em" type="string"/> <element name="strong" type="string"/> <element name="br" type="string"/> </choice> </complexType> </schema>

Ahora, veamos el correspondiente documento instancia con los nuevos atributos incluidos.

<?xml version="1.0"?> <contactos xmlns="http://www.example.com/contactos" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/contactos contactos.xsd" versión="1.0" fuente="Agenda del Banco Bananero del Sur"> <contacto> <persona> <nombre>José</nombre> <apellido1>Pérez</apellido1> <apellido2>García</apellido2> </persona> <localización> <dirección>Ciudad Intermedia, España</dirección> <latitud>34.031892</latitud> <longitud>3.207642</longitud> </localización> <teléfono>955-123-456</teléfono> <conocidos/> <descripción>José es el director de <em>una sucursal</em>.<br/>José es <strong> buena persona </strong></descripción> </contacto> <contacto> <persona> <nombre>Antonio</nombre> <apellido1>Pérez</apellido1> <apellido2>Gutiérrez</apellido2> </persona> <localización> <dirección>Mordor, España</dirección> <latitud>34.123323</latitud> <longitud>4.673839</longitud> </localización> <teléfono>956-654-321</teléfono> <conocidos/> <descripción>Antonio es el apoderado de <em>una sucursal</em>.<br/> A Antonio <strong> le gusta su trabajo </strong></descripción> </contacto> </contacts>

DECLARACIONES <SIMPLETYPE>

Cuando estamos diseñando esquemas XML, podemos necesitar nuestros propios tipos de datos. Como ya hemos visto en el punto anterior, ya hemos hecho esto antes, con <complexType>. Pero se tratan de tipos complejos, es decir, están compuestos de varios tipos de elementos que a su vez tienen sus tipos. También podemos crear tipos de datos simples mediante <simpleType>. Un tipo simple que hemos usado hasta ahora es "string". Los tipos simples se utiliza para asignar tipos a atributos. <simpleType> incluye el atributo "name" que es el nombre del tipo.

Cuando declaramos un <simpleType> tenemos que partir de un tipo de datos existente. Este tipo puede ser un tipo nativo de los esquemas XML o un tipo definido por el usuario. Debido a que los tipos <simpleType> se obtienen a partir de otros, suelen llamarse "tipos derivados". Hay tres tipos derivados primarios:

  • Tipos de restricción
  • Tipos lista
  • Tipos unión

Nosotros vamos a ver únicamente los tipos de restricción.

<simpleType> <restriction base="string"> <enumeration value="Casa"/> <enumeration value="Trabajo"/> <enumeration value="Móvil"/> <enumeration value="Fax"/> </restriction> </simpleType>

Si lo miramos con atención, podemos adivinar las intenciones del programador. Enpecemos con los tipos de restricción.

DECLARACIONES DE RESTRICCIÓN

Se trata del tipo simple más común. Se declaran utilizando la declaración <restriction>. <restriction> tiene un atributo llamado "base" que indica el nombre del tipo simple del que estamos derivando. <restriction> define un subconjunto del tipo base. Así pues, en el ejemplo siguiente, lo que tenemos es un tipo de restricción que restringe los valores del atributo "Clase" a una enumeración de valores posibles de tipo "string".

<attribute name="Clase"> <simpleType> <restriction base="string"> <enumeration value="Casa"/> <enumeration value="Trabajo"/> <enumeration value="Móvil"/> <enumeration value="Fax"/> </restriction> </simpleType> </attribute>

La declaración <enumeration> es llamada "faceta", y además de <enumeration> hay 12 tipos en total:

No vamos a entrar en detalles, para no complicar más las cosas, pero para profundizar más, se puede consultar en http://www.w3.org/TR/xmlschema-2/.

NOTA: Alguien preguntó en clase como crear patrones para restringir los datos. Esto se haría mediante un patrón y expresiones regulares.

CREANDO UN TIPO LOCAL

Crear un tipo local para un atributo es igual que crear un tipo local para un elemento. Para crear un tipo local basta incluir el tipo como hijo del elemento <attribute>. En el siguiente ejemplo, vamos a introducir los tipos simples.

<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:contactos="http://www.example.com/contacts" targetNamespace="http://www.example.com/contactos" elementFormDefault="qualified"> <element name="teléfono"> <complexType> <!-- información del modelo de contenido --> <attribute name="clase"/> <simpleType name="ClaseDeTeléfono"> <restriction base="string"> <enumeration value="Casa"/> <enumeration value="Trabajo"/> <enumeration value="Móvil"/> <enumeration value="Fax"/> </restriction> </simpleType> </complexType> </element> </schema>

El atributo solo tiene una declaración de tipo <simpleType>.

Una instancia válida podría ser la siguiente:

<?xml version="1.0" encoding="UTF-8"?> <telefono xmlns="http://www.example.com/contactos" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/contactos atributos.xsd" clase="Casa"/>

USANDO UN TIPO GLOBAL

El otro modo que hemos visto para declarar el tipo de un atributo es usando un tipo global. Para hacer esto, referenciamos a un tipo nativo de los esquemas XML (como por ejemplo string) o definimos nuestro propio tipo global (dentro de nuestro namespace). A continuación, podemos ver los dos casos:

<attribute name="título" type="string"/>

En este caso hemos usado un tipo nativo de los esquemas XML. En el siguiente ejemplo, definimos nuestro propio tipo global y lo usamos en el atributo:

<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:contactos="http://www.example.com/contacts" targetNamespace="http://www.example.com/contactos" elementFormDefault="qualified"> <simpleType name="ClaseDeTeléfono"> <restriction base="string"> <enumeration value="Casa"/> <enumeration value="Trabajo"/> <enumeration value="Móvil"/> <enumeration value="Fax"/> </restriction> </simpleType> <element name="teléfono"> <complexType> <!-- información del modelo de contenido --> <attribute name="clase" type="contactos:ClaseDeTeléfono"/> </complexType> </element> </schema>

Cuando nos referimos al tipo, debemos incluir el prefijo del espacio de nombres (si es que hay). En el ejemplo anterior, usamos el prefijo "contactos" para referirnos al target namespace. En cualquier caso el siguiente ejemplo es también correcto:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.com/contacts" targetNamespace="http://www.example.com/contacts" elementFormDefault="qualified"> <xs:simpleType name="ClaseDeTeléfono"> <!-- type information --> </xs:simpleType> <xs:element name="teléfono"> <xs:complexType> <!-- Modelo de contenido --> <xs:attribute name="clase" type="ClaseDeTeléfono"/> </xs:complexType> </xs:element> </xs:schema>

En este caso se ha usado el prefijo xs para el espacio de nombres de los esquemas XML y no se usa prefijo para el target namespace. Por ello, no es preciso poner prefijo a "ClaseDeTeléfono".

REFERENCIAS A UN ATRIBUTO GLOBAL

Podemos reusar definiciones de tipos simples definidos globalmente, como hemos visto, pero si preferimos reusar definiciones completas de atributos, también podemos. Como ya nos podemos imaginar, usaremos el atributo ref. Observa el siguiente ejemplo:

<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:contactos="http://www.example.com/contactos" targetNamespace="http://www.example.com/contactos" elementFormDefault="qualified"> <attribute name="clase"> <simpleType> <!-- tipo de información --> </simpleType> </attribute> <element name="teléfono"> <complexType> <!-- información del modelo de contenido --> <attribute ref="contactos:clase"/> </complexType> </element> </schema>

Se ha definido un atributo global, llamado clase, que contiene una definición de tipo. Después, en el tipo complejo donde se define un atributo similar al global, se hace una referencia a este.

Como ya hemos visto, los nombres de atributo deben estar cualificados con el espacio de nombres adecuado. Cuando nos referimos a un atributo global, no hay atributo type, y no es necesaria una definición de tipo local. El atributo utiliza el tipo del atributo referenciado.

Actividad 8. Introduce en el esquema del ejercicio 7 los atributos necesarios para poder introducir la siguiente información. Después modifica la instancia.

  • Cada contacto está identificado mediante una cadena de texto llamada idPersona.
  • Cada persona tiene un atributo etiqueta que puede contener cosas como responsabilidades o títulos de cortesía...