ESQUEMAS (II)

CARDINALIDAD

Tal y como se hacía en los DTD, es posible definir la cardinalidad de un elemento, es decir, cuantas veces puede o debe aparecer. En los esquemas XML, se puede moficiar la cardinalidad XML mediante los atributos "minOccurs" y "maxOccurs". Por ejemplo:

<element name="nombre" type="string" minOccurs="2" maxOccurs="2"/> <element ref="target:nombre" maxOccurs="10"/> <element name="dirección" minOccurs="0" maxOccurs="unbounded"/>

En el primer caso, se declara que el elemento nombre puede aparecer en la instancia exactamente 2 veces. En el segundo, se indica que el elemento está usando una referencia a la declaración global de "nombre". Incluso si se ha declarado usando "ref", se puede definir la cardinalidad. En este caso, como mínimo aparecerá 1 vez (no declarar minOccurs es igual a decir minOccurs="1") y como máximo 10. El último ejemplo especifica la dirección puede o no aparecer, y que si aparece, puede hacerlo tantas veces como quiera (unbounded).

Los atributos minOccurs y maxOccurs no están permitidos dentro de declaraciones de elementos globales. En vez de esto, se pueden usar estos atributos en elementos que referencian a los primeros. Es el caso del segundo ejemplo anterior. Por ejemplo:

<complexType name="TipoNombre"> <sequence> <element ref="target:nombre" minOccurs="1" maxOccurs="2"/> <element ref="target:apellido1"/> <element ref="target:apellido2" minOccurs="0" maxOccurs="1"/> </sequence> <attribute name="título" type="string"/> </complexType>

En el ejemplo anterior se indica mediante la cardinalidad que el elemento nombre es obligatorio, y puede tener un máximo de 2 ocurrencias. El elemento apellido1 es obligatorio. Y por último, el elemento apellido2 es opcional.

VALORES FIJOS

Se pueden declarar valores fijos tanto para atributos como para elementos. Si se declara un elemento o un atributo fijo siempre tendrán el mismo valor. Y si no se incluye este valor, el analizador sintáctico añadirá el valor automáticamente. Poner un valor diferente devolverá un error. El siguiente ejemplo muestra como definir un valor fijo para un elemento (para un atributo sería igual):

<element name="version" type="string" fixed="1.0"/>

El la instancia de documento, serían legales las siguientes líneas:

<version>1.0</version> <version></version> <version/>

En las dos últimas se añadiría el valor 1.0. Pero escribir <version>1.2</version> devolvería un error.

DECLARACIONES <COMPLEXTYPE>

En los ejemplos anteriores, hemos visto de pasada la declaración de elementos. En estas declaraciones, aparecían las definiciones <complexType>. Dentro de <complexType> se pueden especificar los elementos permitidos en el contenido de un elemento.

<complexType> permite los atributos "mixed" y "name". El atributo "mixed" puede valer "true" o "false". En un momento entramos en ello.

Por ejemplo:

<?xml version="1.0"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:target="http://www.example.com/persona" targetNamespace="http://www.example.com/persona" elementFormDefault="qualified"> <element name="persona"> <complexType> <sequence> <element name="nombre" type="string"/> <element name="apellido1" type="string"/> <element name="apellido2" type="string"/> </sequence> <attribute name="título" type="string"/> </complexType> </element> </schema>

Como esta es una declaración local, no hemos incluido el atributo nombre en "complexType". Las definiciones locales nunca tienen nombre, y son llamadas "tipos complejos anónimos".

En cambio, las declaraciones "complexType" globales siempre utilizan el atributo nombre. Observa el siguiente ejemplo:

<?xml version="1.0"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:target="http://www.example.com/persona" targetNamespace="http://www.example.com/persona" elementFormDefault="qualified"> <element name="nombre" type="string"/> <element name="apellido1" type="string"/> <element name="apellido2" type="string"/> <complexType name="TipoNombre"> <sequence> <!-- Aquí hacemos referencia a los elementos globales anteriormente definidos, nombre, apellido1 y apellido2 --> <element ref="target:nombre"/> <element ref="target:apellido1"/> <element ref="target:apellido2"/> </sequence> <attribute name="título" type="string"/> </complexType> <element name="persona" type="target:TipoNombre"/> </schema>

Las definiciones también pueden usarse para crear modelos de contenido mixto y vacío. El contenido mixto nos permite incluir tanto texto como elementos. Para crear un modelo de contenido mixto, hay que incluir el atributo mixed="true". Por ejemplo:

<element name="descripción"> <complexType mixed="true"> <choice minOccurs="0" maxOccurs="unbounded"> <element name="em" type="string"/> <element name="strong" type="string"/> <element name="br" type="string"/> </choice> </complexType> </element>

En este ejemplo declarado como "descripción", el elemento puede contener un infinito número de <em>, <strong> y <br>. Además, puede haber texto intercalado gracias al atributo mixed="true". Es decir, un elemento descripción válido podría ser:

<description> Juan es el <em> director </em> de la sucursal del banco <strong> Bananero </strong> </description>

El analizador con validación ignorará el contenido textual.

Para declarar un modelo de contenido vacío en una definición <complexType>, sencillamente hay que dejarla vacía. Por ejemplo:

<element name="conocidos"> <complexType/> </element>

En este caso, el elemento "conocidos" nunca contendrá texto o elementos hijo.

DECLARACIONES <GROUP>

Además de <complexType>, los esquemas permiten definir grupos de elementos reutilizableas. Creando una declaración global <group>, se puede reusar y combinar modelos de contenido. El elemento <group> solo permite el atributo "name". Como ya comentamos antes, las declaraciones globales tienen que tener un nombre, así que los <group> no son menos. Veamos este ejemplo:

<?xml version="1.0"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:target="http://www.example.com/persona" targetNamespace="http://www.example.com/persona" elementFormDefault="qualified"> <group name="GrupoNombre"> <sequence> <element name="nombre" type="string"/> <element name="apellido1" type="string"/> <element name="apellido2" type="string"/> </sequence> </group> <complexType name="TipoNombre"> <group ref="target:GrupoNombre"/> <attribute name="title" type="string"/> </complexType> <element name="persona" type="target:TipoNombre"/> </schema>

Si observamos bien este ejemplo, veremos que primero se define un <group>, que es reutilizado por un <complexType> que finalmente es reutilizado por un <element>.

MODELOS DE CONTENIDO

Ya hemos visto que podemos usar <complexType> y <group> para especificar el contenido válido de un elemento. Ahora vamos a ver como crear modelos de contenido más avanzados que los que permitían los DTD. Para ello podemos usar los siguientes tipos de declaraciones:

<sequence> <choice> <group> <all>

Empecemos con <sequence>

DECLARACIONES <SEQUENCE>

Como vimos con los DTD, especificar un modelo de contenido usando una secuencia de elementos es muy simple. De hecho, esta etiqueta ha ido apareciendo por los diferentes esquemas que hemos visto. <sequence> soporta los atributos "minOccurs" y "maxOccurs", y creo que no tengo que decir para qué, ¿No?

<sequence> puede contener:

  • declaraciones <element>,
  • declaraciones <choice>,
  • referencas a <group> y
  • otras declaraciones <sequence>

Hablaremos de ello más adelante.

Se pueden tener secuencias dentro de secuencias que están dentro de secuencias, o se puede tener varias <choices> dentro de secuencias que están dentro de grupos (casi cualquier combinación que se nos ocurra).

Un ejemplo, como el ya visto hasta ahora, puede ser el siguiente:

<sequence> <element name="nombre" type="string" minOccurs="1" maxOccurs="unbounded"/> <element name="apellido1" type="string" minOccurs="1" maxOccurs="1"/> <element name="apellido2" type="string" minOccurs="1" maxOccurs="1"/> </sequence>

Según la declaración anterior, la siguiente instancia sería correcta:

<nombre> Juan </nombre> <apellido1> García </apellido1> <apellido2> Rodríguez </apellido2>

Sin embargo la siguiente instancia sería incorrecta:

<apellido1> García </apellido1> <nombre> Juan </nombre> <apellido2> Rodríguez </apellido2>

por el hecho de que aparecen en distinto orden.

Práctica 3. Crea un esquema para la siguiente instancia:

<Personas> <Persona> <nombre> Linux </nombre> <apellido> Torvalds </apellido> <descripción> Creador del kernel de GNU/Linux </descripción> </Persona> <Persona> <nombre> Alan </nombre> <apellido> Cox </apellido> <descripción> Programador implicado en el kernel de GNU/Linux </descripción> </Persona> <Persona> <nombre> Richard </nombre> <apellido> Stallman </apellido> <descripción> Iniciador del proyecto GNU </descripción> </Persona> </Personas>

Entrega el esquema con el nombre Act3-esquemas.xsd

Práctica 4.Reestructura el ejercicio anterior, para que el tipo de "Persona" esté definido globalmente.

Entrega el esquema con el nombre Act4-esquemas.xsd

Práctica 5. Reestructura el ejercicio anterior, de modo que ahora definas globalmente los elementos "nombre", "apellido" y "descripción".

Entrega el esquema con el nombre Act5-esquemas.xsd

Saludos.