XML Schema (XSD)

De MediaWiki
Ir a la navegación Ir a la búsqueda


Introdución

O XML Schema Definition Language (XSDL) é unha linguaxe XML recomendada polo W3C, creada para describir a estrutura e restriccións do contido dun documento XML. XSDL permite especificar os tipos de datos dos elementos dun documento XML e mellora en moitos aspectos a validación de documentos de DTDs.

Os ficheiros nos que definimos os esquemas XML teñen extensión XSD (XML Schema Definition)e son en si mesmos documentos XML.

Cando se valida un documento XML que ten vinculado un esquema XML en realidade se están realizando dúas validacións, xa que o documento XML valídase co esquema XML, e éste a súa vez validaríase cun hipotético XMLSchema.xsd, xa que ten que cumplir a sintaxe dos esquemas XML.

XML Schema é unha alternativa baseada en XML ao uso de DTD, permitindo definir os elementos válidos dun documento XM ao igual que o facía un DTD, pero con mellores posibilidades.

Ventajas

Os esquemas XML pretenden solucionar os principais problemas das DTD, polo que teñen varias ventaxas:

  • Permiten validar o contido dos campos do documento
  • Facilitan o procesamento dos documentos XML por parte de linguaxes de programación que usen reglas estrictas para definir os tipos de datos utilizados.
  • Únicamente necesitamos un parseador para cotexar o documento XML e a definición do seu esquema xa que ambos son XML.
  • Permiten definir secuencias de elementos que poden aparecer en calquera orde: (nome, idade, peso), (idade, nombe, peso), (nombe, peso, idade) ou calquera outra combinación.
  • Nas DTDs os elementos defínense a nivel de documento, polo que no podemos ter nun mesmo documento dous elementos con fillos que teñan o mesmo noe. Os esquemas XML permiten realizar declaracións “sensibles ao contexto”.
  • Os esquemas XML soportan o uso de espazos de nomes e permiten formar claves a partir de varios atributos ou nomes.

Estrutura dun XSD

A modo introcutorio, esta é a estrutura dun XSD

Veremos a continuación en máis detalle o seu funcionamento.

Vinculación del XSD desde el XML

Tenemos dos formas de vincular un documento XML con su xsd en función del si el documento tiene o no su propio espacio de nombres:

  • Si el documento XML no tiene su propio espacio de nombres:
  • En el esquema (en el archivo xsd) usaremos el espacio de nombres XMLSchema (http://www.w3.org/2001/XMLSchema), que se referencia por convención con el prefijo xs (se podría usar cualquier otro), para definir los elementos y tipos de datos simples predefinidos (por ejemplo xs:string, para poder identificarlos como elementos del lenguaje del esquema XML, que sería como identificarlos como “palabras reservadas”).
<?xml version="1.0" ... ?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    ... definición do esquema ... 
</xs:schema>

No documento XML tedremos que utilizar o espazo de nombs XMLSchema-instance (http://www.w3.org/2001/XMLSchema-instance), que se referencia co prefijo xsi, para poder usar no elemento raíz o atributo xsi:noNamespaceSchemaLocation que nos permite indicar en qué ficheiro está definido o esquema.

<?xml version="1.0" ... ?>
<elementoRaíz
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="esquema.xsd"> ... 
</elementoRaíz>

Por exemplo:

esquemaGuarderia.xsd 
<?xml version="1.0"?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="guarderia"> ... 
</xs:schema> 

Documento guarderia.xml 
<?xml version="1.0"?>
<guarderia xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="esquemaGuarderia.xsd">
    <niño numeroExpediente="323"> 
    ... 
</guarderia>

Se queremos que os elementos definidos no esquema pertenzan a un certo espazo de nomes usaremos o atributo targetNamespace na definición do elemento raíz para indicar o espazo de nombres que usaremos para validalo.

<?xml version="1.0" ... ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="URIdelEspazoDeNomes"> 
  ... definición do esquema ... 
</xs:schema>

E no documento crearemos e utilizaremos nos elementos un prefixo para o espazo de nomes.

<?xml version="1.0" ... ?>
<pref:elementoRaíz
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:pref="URIdelEspazoDeNomes" xsi:schemaLocation="URIdoEspazoDeNomes esquema.xsd"> ... 
</pref:elementoRaíz>

Definición do XSD

O esquema XML consta dun elemento raíz (guardería) e un conxunto de subelementos (nenos) que poderían conter a súa vez outros subelementos (nome, datanacemiento, peso, altura) ou un valor de un tipo de datos simple.

Os elementos que conteñen subelementos ou atributos denomínanse tipos complexos; os que teñen valores son tipos simples.

Os atributos dos elementos son sempre dalgún tipo de datos simple.

Un esquema XML tería esta apariencia:

<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="guarderia">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="neno" minOccurs="1" maxOccurs="50" type="tipoNeno"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="tipoNeno">
        <xs:sequence>
            <xs:element name="nome" type="xs:string"/>
            <xs:element name="datanacemento" type="xs:date"/>
            <xs:element name="peso" type="xs:decimal"/>
            <xs:element name="altura" type="xs:unsignedByte"/>
            <xs:element name="vacinas" type="xs:boolean"/>
        </xs:sequence>
        <xs:attribute name="numeroExpediente" type="xs:unsignedShort"/>
    </xs:complexType>
</xs:schema>

Tipos de datos

Existen catro construccións básicas nas que se basea un esquema:

  • Declaración de elementos: para asociar o nome dun elemento a un tipo predefinido, a un tipo simple ou a un tipo complexo.
  • Declaración de atributos: para asociar o nombe dun atributo a un tipo simple (o valor dos atributos so pode conter texto).
  • Tipos simples: existen varios timpos simples predefinidos (string, integer, decimal, etc), pero é tamén posible definir novos tipos baseados nos tipos simples predefinidos, aplicándolles certas restriccións. Nos tipos simples definidos o seu valor sempre é de tipo texto e non poden conter outros elementos nin atributos.
  • Tipos complexos: para definir novos tipos de datos con valores que constan de atributos e/ou elementos (tamén poden incluir texto no seu contido).

Declaración de elementos XML

Para declarar un elemento XML no esquema utilízaase a etiqueta <xs:element ...>.

Podemos declarar os tipos de datos de xeito global ou local.

Nunha declaración global os elementos son fillos do elemento raíz do esquema XML (xs:schema), polo que poden utilizarse en calquier lugar do documento. Cuando declaramos o elemento, indicamos o seu tipo de datos por medio dos atributos type ou rel:

<xs:element name="enderezoPrincipal" type="tipoEnderezo"/>
<xs:element name="enderezos">
    <xs:sequence>
        <xs:element ref="tipoDEnderezo" minOccurs="0"/>
    </xs:sequence>
</xs:element>
<xs:complexType name="tipoEnderezo">
    <xs:sequence>
        <xs:element name="rúa" type="xs:string"/>
        <xs:element name="numero" type="xs:unsignedShort"/>
        <xs:element name="localidade" type="xs:string"/>
    </xs:sequence>
    <xs:attribute name="provincia" type="xs:NMTOKEN" fixed="Pontevedra"/>
</xs:complexType>

Unha declaración local defínese dentro dun elemento polo que aplica únicamente a ese elemento. Dise que son tipos anónimos xa que non teñen un nome.

<xs:element name=”nomeElemento”>
    <xs:simpleType> ... </xs:simpleType>
</xs:element>

Dependendo do tipo de elemento do que se trate podemos declaralo dalgún dos seguintes xeitos:

  • Baseados nun tipo predefinido: so poden tomar un valor que cumpla as restriccións do tipo no que se basa. Non se permiten nin (sub)elementos nin atributos.
<xs:element name="nomeElemento" type="tipoPredefinido" />

Por exemplo:

<xs:element name="nomeCurso" type="xs:string"/> 
<xs:element name="númeroAsistentes" type="xs:nonNegativeInteger"/>
  • Baseados nun tipo simple definido polo usuario: so pode tomar un valor que cumpla as restriccións impostas polo tipo simple definido polo usuario. Tampouco permiten nin (sub)elementos nin atributos.
  • Basados en un tipo complexo: será necesario definir un tipo complexo cando un elemento conteña atributos ou outros elementos. A declaración dun elemento baseado nun tipo complexo é exactamente igual á dun tipo simple, cambiando <xs:simpleType> por <xs:complexType>, pero ademáis permite definir subelementos e atributos.

Declaración de atributos

Na declaración dun elemento <xs:element ... > podemos especificar atributos. Os máis usados son:

  • name: o nombre do elemento, que se usará nos documentos XML encerrado entre os símbolos <>.
  • type: o tipo de datos que asignamos ó elemento
  • ref: su valor é o nome doutro elemento definido no esquema (ou en otro esquema especificando o seu espazo de nombs). Si se especifica este atributo, non se poderán indicar os atributos default, fixed ou type, nin conter os elementos <simpleType> ou <complexType>.
 <xs:element ref="nomeDoElementoReferenciado"/>
  • maxOccurs: número máximo de veces que o elemento pode aparecer dentro do elemento que a súa vez o contén. O seu valor debe ser de tipo nonNegativeInteger ou ben a cadea unbounded para que non teña límite. Por defecto é 1.
 <xs:element name="liña" type="xs:string" maxOccurs="unbounded"/>
  • minOccurs: número mínimo de veces que o elemento debe aparecer dentro do elemento que a súa vez o contén. O seu valor debe ser de tipo nonNegativeInteger. Co valor 0 convírtese nun elemento opcional. Por defecto é 1.
 <xs:element name="dataDeNacemiento" type="xs:date" minOccurs="0"/>
  • default: permite especificar un valor por defecto para o elemento.
 <xs:element name="númeroDeCopias" type="xs:positiveInteger" default="1"/>
  • fixed: o seu valor é automáticamente asignado ó contido do elemento sen poder cambiarse no documento. Este atributo non é compatible simultáneamente coatributo default.
  • use: para determinar se o elemento ou atributo é obrigatorio (required) ou opcional (optional)

Tipos simples

Son tipos de datos que conteñen un so valor, que pode ser dun tipo predefinido (entero, cadea, data, etc) ou ben dun tipo de datos máis específico definido polo usuario.

Os tipos de datos simples predefinidos máis empregados son:

Texto
xs:string cadena de caracteres alfanumérica
xs:normalizedString os caracteres de nova liña, tabulador e retorno de carro son convertidos
a espazos en branco antes do procesamento do esquema.
xs:anyURI unha URI
Números
xs:byte tipos numéricos de menor a maior tamaño
xs:short
xs:integer
xs:long
xs:unsignedByte números sin signo
xs:unsignedInt
xs:unsignedShort
xs:unsignedLong
xs:positiveInteger valor estrictamente maior que 0
xs:negativeInteger valor estrictamente menor que 0
xs:nonPositiveInteger valor menor ou igual a 0
xs:nonNegativeInteger valor maior ou igual a 0
xs:decimal tipos decimales. Coma separador decimal emprégase o punto.
xs:float
xs:double
Data/hora
xs:date data con formato “AAAA-MM-DD”
xs:time hora con formato “hh:mm:ss”
xs:dateTime data e hora, con formato ISO 8601 (separados por unha T: 2010-04-14T00:19:25)
xs:gDay día
xs:gMonth mes
xs:gYear ano
xs:gYearMonth mes do ano
xs:gMonthDaydía día do mes


Lóxicos
xs:boolean acepta os valores true ou 1 e false ou 0

Tipos simples personalizados

Ademáis dos tipos de datos simples predefinidos podense definir tipos de datos simples propios.

Existen tres mecanismos para crear tipos simples personalizados:

  • restriccións
  • listas
  • unións

Restriccións

A sintaxe para definir un tipo simple con restriccións é a seguinte:

<xs:simpleType name="nomeTipoSimple">
    <xs:restriction base="tipoBase">
    ...
    </xs:restriction>
</xs:simpleType>

As restriccións que podemos aplicar son as seguintes:

Restriccións
RESTRICCIÓN DESCRIPCIÓN
length Número exacto de caracteres da cadea ou número mínimo de elementos da lista permitidos. Debe ser igual ou maior que cero
minLength Número mínimo de caracteres da cadea ou número mínimo de elementos da lista permitidos. Debe ser igual ou maior que cero
maxLength Número máximo de caracteres da cadea ou número máximo de elementos da lista permitidos. Debe ser igual ou maior que cero
pattern O contido debe encaixar cunha expresión regular
enumeration Define unha lista de valores válidos
whiteSpace Permite indicar cómo queremos que o validador trate os espazos en branco, saltos de liña, tabuladores, espazos e retornos de carro. Hai tres valores:
preserve (conservaos)
replace (sustitue grupos de espazos en branco por espazos en branco simples)
collapse (sustitue grupos de espazos en branco, tabuladores e saltos de liña por espazos en branco simples, e elimina espazos iniciais e finales)
minInclusive Límite inferior incluido do valor numérico (debe ser maior ou igual ó valor indicado)
minExclusive Límite inferior do valor numérico (debe ser maior ó valor indicado)
maxInclusive Límite superior incluido do valor numérico (debe ser menor ou igual ó valor indicado)
maxExclusive Límite superior do valor numérico (debe ser menor ó valor indicado)
totalDigits Máximo número de díxitos nos tipos numéricos. Debe ser maior que 0
fractionDigits Máximo número de decimais nos tipos numéricos. Debe ser maior ou igual que 0

Dependendo do tipo base poderanse aplicar unhas restriccións ou outras.

  • Sobre cadeas: length, minLength, maxLength, pattern, enumeration e whitespace
<xs:simpleType name="nomeCurto">
    <xs:restriction base="xs:string">
        <xs:maxLength value="12"/>
    </xs:restriction>
</xs:simpleType>

Sobre números: totalDigits, pattern, whitespace, enumeration, maxInclusive, maxExclusive, minInclusive y minExclusive.

<xs:simpleType name="nomeCurto">
    <xs:restriction base="xs:string">
        <xs:maxLength value="12"/>
    </xs:restriction>
</xs:simpleType>
<xs:element name="nota">
    <xs:simpleType>
        <xs:restriction base="xs:byte">
            <xs:minInclusive value="0"/>
            <xs:maxInclusive value="10"/>
        </xs:restriction>
    </xs:simpleType>
</xs:element>

Cando utilizamos a restricción pattern usaremos expresións regulares para determinar qué caracteres podemos usar, cantos ou en qué lugar irá cada caracter:

Restricción pattern
Patrón Descrición Exemplo de patrón Patrón coincidente
^ Coincidencia ó principio da cadena ^Isto Isto é unha cadea
$ Coincidencia ó final da cadena final$ Coincidencia ó final
* O caracter que o precede pode aparecer 0, 1 ou más veces ma* m, ma, maa, etc
O carácter que o precede debe aparecer 1 ou máis veces ma+ ma, maa, etc
? O carácter que o precede pode aparecer 0 ou 1 vez ma? ma ou m
[...] Calquier caracter dentro dos paréntesis a[px]e ape ou axe
[ - ] Indica un rango de caracteres [c-k]a ca,da,ea,fa,ga,ha, ia ou ka
[^...] Calquier caracter menos os que están entre paréntesis a[^px]e ale, a1e, etc
[^ - ] Calquier caracter menos os que estén nese rango [^c-k]a ba, la, etc
{n} O carácter que o precede debe aparecer exactamente n veces ma{2} maa
{n,} O carácter que o precede debe aparecer n ou máis veces bu{2,} maa, maaa, etc
{n,m} O carácter que o precede debe aparecer como mínimo n e como máximo m veces [0-9]{2,4} 32, 4444
(...) Permite agrupar caracteres para aplicarlles os patróns anteriores (ca){2}túa cacatúa
escapar barra Permite separar alternativas válidas MP MP ou M9
\d Calquera díxito (equivalente a [0-9]) \d{2} 23
\D Calquera non díxito \D{2}M L_M ou ABM
\w Calquera letra ou díxito ala\w ala4 ou alag
\W Cualquier caracter diferente de letra o dígito M\Wa M-a
Calquer caracter salvo salto de liña
Salto de liña
Caracter en blanco, tabulador ou salto de liña

Listas

Unha lista é unha secuencia de valores dun determinado tipo separados por espazos. A sintaxis para crear unha lista é:

<xs:simpleType name="nomeTipoLista">
    <xs:list itemType="tipoDatos"/>
</xs:simpleType>

No tipo de datos poderíamos usar calquera tipo de datos, predefinido ou definido polo usuario:

<xs:simpleType name="nota">
    <xs:restriction base="xs:byte">
        <xs:minInclusive value="0"/>
        <xs:maxInclusive value="10"/>
    </xs:restriction>
</xs:simpleType>
<xs:simpleType name="listaNotas">
    <xs:list itemType="nota"/>
</xs:simpleType>

Para asignarlle valores ó elemento no documento XML:

<listaNotas>2 5 7 5 9</listaNotas>

Aos tipos lista pódenselle aplicar as seguintes propiedades:

  • length: lonxitude da lista
  • minLength: lonxitude mínima
  • maxLength: lonxitude máxima
  • enumeration: enumeración de posibles valores

Se queremos unha lista de tres notas para gardar as notas de cada avaliación dun alumno, podemos crear un novo tipo de datos simple restrinxindo o tipo "listaNotas" para que so teña tres elementos:

<xsd:simpleType name="listaNotas">
    <xsd:list itemType="nota"/>
</xsd:simpleType>
<xsd:simpleType name="notasCurso">
    <xsd:restriction base="listaNotas">
        <xsd:length value="3"/>
    </xsd:restriction>
</xsd:simpleType>

Aínda que utilizar listas pode facilitar as cousas en certos aspectos, non se recomenda a súa utilización en XML xa que perdense as vantaxes da linguaxe. Pola contra debense engadir máis marcas para definir o elmento:

<notasCurso> 
  <nota>5</nota> 
  <nota>9</nota> 
  <nota>4</nota> 
</notasCurso>

Unión

As unións permiten crear elementos que poden tomar valores de distintos tipos de datos.

A súa sintaxe:

<xs:simpleType name="nombreTipoUnion">
    <xs:union>
        <xs:simpleType> ... </xs:simpleType>
        <xs:simpleType> ... </xs:simpleType> 
         ...
    </xs:union>
</xs:simpleType>

Por exemplo, podemos definir un tipo de moeda que poida tomar valores integer ou float:

<xs:element name="moeda">
    <xs:simpleType>
        <xs:union memberTypes="integer float" />
    </xs:simpleType>
</xs:element>

As posibles notas dun alumno que poden tomar un valor entero do 0 ó 10, ou un NP (Non Presentado):

<xs:simpleType name="tipoNota">
    <xs:union>
        <xs:simpleType>
            <xs:restriction base="xs:integer">
                <xs:maxInclusive value="0"/>
                <xs:minInclusive value="10"/>
            </xs:restriction>
        </xs:simpleType>
        <xs:simpleType>
            <xs:restriction base="xs:string">
                <xs:enumeration value="NP"/>
            </xs:restriction>
        </xs:simpleType>
    </xs:union>
</xs:simpleType>

Tipos complexos

Os tipos complexos permiten definir elementos que conteñen atributos e/ou elementos anidados, e que se definen por medio do tipo complexType.

Os elementos se decláranse co elemento element e os atributos co elemento attribute:

<xs:complexType name="tipoEnderezo">
    <xs:sequence>
        <xs:element name="rúa" type="xsd:string"/>
        <xs:element name="número" type="xsd:unsignedShort"/>
        <xs:element name="localidade" type="xsd:string"/>
    </xs:sequence>
    <xs:attribute name="provincia" type="xsd:NMTOKEN" fixed="Pontevedra"/>
</xs:complexType>

Varios elementos dun XML poden ter o mismo tipo complexo (poderíamos ter un XML con enderezoCasa e enderezoTraballo e poderíamos asignarlle a ambas o tipoEnderezo do exemplo).

Un elemento complexo pode conter atributos, subelementos e incluso contido propio en forma de texto.

Atributos

Os atributos dun tipo complexo defínense dentro do tipo complexo. Xa que os atributos so poden ter valores de tipo simple, a súa definición pódese facer asignándolle un tipo de datos simple predefinido:

<xs:attribute name="nomeAtributo" type="tipoDoAtributo" [default=”valorPorDefecto” | fixed=”valorFiXo”] [use=”required”] />

Ou asignándolle un tipo de datos definido polo usuario:

<xs:attribute name="nombreAtributo" [default=”valorPorDefecto” | fixed=”valorFijo”] [use=”required”] >
    <xs:simpleType>
        <xs:restriction type=”tipoSimple”> ... </xs:restriction>
    </xs:simpleType>
</xs:attribute>
<xs:element name="distancia">
    <xs:complexType>
        <xs:attribute name="unidad" type="xsd:string"/>
        <xs:attribute name="valor" type="xsd:decimal"/>
    </xs:complexType>
</xs:element> --- 
<distancia unidad="Km" valor="444.23"/>

Subelementos

Os tipos complexos poden ter subelementos. Cos atributos minOccurs e maxOccurs configuramos que poida aparecer varias veces ou aparecer canda menos un número determinado de veces. Por defecto o valor de ambos é 1 (é obrigatorio e so pode aparecer unha vez), pero podemos modificalos para indicar o número de aparicións que queramos (de xeito similar aos operadores + e * da DTD).

<xs:element name="observacións" type="xs:string" minOccurs="0" maxOccurs="4"/>

Cando un tipo complexo ten varios subelementos estes poden agregarse de distintos xeitos:

  • sequence: Unha secuencia ordeada de elementos que deben aparecer sempre na mesma orde.
  • choice: Un grupo de elementos dos que so pode aparecer uno
<xs:complexType name="persona">
    <xs:choice>
        <xs:element name="apodo" type="xs:string"/>
        <xs:sequence>
            <xs:element name="nome" type="xs:string"/>
            <xs:element name="apelido1" type="xs:string"/>
            <xs:element name="apelido2" type="xs:string" minOccurs=”0”/>
        </xs:sequence>
    </choice>
</xs:complexType>
  • all: Unha secuencia desordeada de elementos que poden aparecer en calquer orde. Se un elemento complexo ten un grupo de subelementos de tipo all, este debe aparecer como fillo único do elemento principal (non pode ter diante un sequence e despois o all, por exemplo, o aparece un sequence e dentro do sequence o all).
<xs:element name="persona">
    <xs:complexType>
        <xs:all>
            <xs:element name="nif" type="xs:string"/>
            <xs:element name="nome" type="nomeCompleto"/>
        </xs:all>
    </xs:complexType>
</xs:element>

Serían válidos:

<persona>
    <nomeCompleto>
        <nome>Pepe</nome>
        <apelido1>Blanco</apelido1>
    </nomeCompleto>
    <nif>11111111H</nif>
</persona>

<persona>
    <nif>11111111H</nif>
    <nomeCompleto>
        <nome>Pepe</nome>
        <apelido1>Blanco</apelido1>
    </nomeCompleto>
</persona>
  • any: permite que o esquema acepte nese lugar calquer elemento e o seu contido. Esta estrutura tene atributos que permiten configurar que acepte únicamente elementos de certos espacios de nomes, ou ben que a validación do contido sexa máis o menos ríxida. Por exemplo, se quixeramos definir un elemento que conteña un código HTML, sexa cal sexa, podemos definilo de forma que acepte calquier elemento do espzio de nomes “http://www.w3.org/1999/xhtml”:
<?xml version = "1.0" encoding = "utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="persona">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="nome" type="xs:string"/>
                <xs:element name="apelido1" type="xs:string"/>
                <xs:element name="apelido2" minOccurs="0" type="xs:string"/>
                <xs:element name="comentario" type="tipoComentario"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="tipoComentario">
        <xs:sequence>
            <xs:any namespace="http://www.w3.org/1999/xhtml" minOccurs="1" maxOccurs="unbounded" processContents="skip" />
        </xs:sequence>
    </xs:complexType>
</xs:schema> 

-- XML 
<?xml version="1.0" encoding="UTF-8"?>
<persona xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:html="http://www.w3.org/1999/xhtml" xsi:noNamespaceSchemaLocation="a.xsd">
    <nome>Andrea</nomb>
    <apelido1>Villar</apelido1>
    <apelido2>López</apelido2>
    <comentario>
        <html:p>
            <html:b>Repetidor</html:b> cun módulo pendente. 
        </html:p>
    </comentario>
</persona>

Podemos utilizar tamén anyAttribute para indicar que o elemento pode conter calquer atributo:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="persona">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="nome" type="xs:string"/>
                <xs:element name="apelido1" type="xs:string"/>
                <xs:element name="apelido2" minOccurs="0" type="xs:string"/>
            </xs:sequence>
            <xs:anyAttribute processContents="skip"/>
        </xs:complexType>
    </xs:element>
</xs:schema> 

--XML 
<?xml version="1.0" encoding="UTF-8"?>
<persona xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocation="ejemploAnyAttribute.xsd" sexo="femenino">
    <nome>Nerea</nome>
    <apelido1>Gómez</apelido1>
    <apelido2>Rodríguez</apelido2>
</persona>

Elementos con contido simple

Son elementos que teñen texto e atributos. No interior do contido indicaremos se queremos extender ou restrinxir o tipo base. Para iso empregaremos as etiquetas <xs:extension base=”tipoBaseExtendido”> ou <xs:restriction base=”tipoBaseRestringido”>.

<xs:complexType name=”distanciaConUnidades”>
    <xs:simpleContent>
        <xs:extension base="xs:integer">
            <xs:attribute name="unidade" type="xs:string" />
        </xs:extension>
    </xs:simpleContent>
</xs:complexType>
<xs:element name="distancia" type=”distanciaConUnidades”/>

--XML
<distancia unidade="Km">32</distancia>

Elementos con contido complexo

O elemento pode conter texto, subelementos e atributos. Este tipo de elementos denomínanse mixtos e deben declararse co atributo mixed=”true”.

<xs:element name="carta">
    <xs:complexType mixed="true">
        <xs:sequence>
            <xs:element name="nombe" type="xs:string"/>
            <xs:element name="fillo" type="xs:string"/>
            <xs:element name="numero" type="xs:unsignedShort"/>
            <xs:element name="data" type="xs:date"/>
        </xs:sequence>
    </xs:complexType>
</xs:element> --- 
<carta> Estimada Sra.
    <nome>Alba Luces</nome>. A presente carta é para notificarlle que a súa filla 
    <fillo>Laura</fillo> ten un total de 
    <numero>4</numero> faltas desde o día 
    <data>13/4/20</data>. 
</carta>

Outros elementos da linguaxe

Grupos

Os grupos poden empregarse para definir conxuntos relacionados de elementos (group) ou conxuntos relacionados de atributos (attributeGroup). Son útiles para facer referencia a eles desde outros elementos.

Un grupo de atributos pode conter outros grupos de atributos.

Un exemplo de grupo de elementos sería:

<xs:group name="nomeCompleto">
    <xs:sequence>
        <xs:element name="nome" type="xs:string"/>
        <xs:element name="apelido1" type="xs:string"/>
        <xs:element name="apelido2" type="xs:string" minOccurs=”0”/>
    </xs:sequence>
</xs:group>

Posteriormente poderíamos facer referencia a él do seguinte xeito:

<xs:element name="alumno" type="tipoAlumno"/>
<xs:complexType name="tipoAlumno">
    <xs:all>
        <xs:group ref="nomeCompleto" />
        <xs:element name="numeroExpediente" type="xs:string"/>
        <xs:element name="curso" type="xs:string"/>
    </xs:all>
</xs:complexType>

Un exemplo completo, cun grupo de atributos:

--XSD: 
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:attributeGroup name="caracteristicas">
        <xs:attribute name="duracion" type="xs:unsignedShort"/>
        <xs:attribute name="grado">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                    <xs:enumeration value="básico"/>
                    <xs:enumeration value="medio"/>
                    <xs:enumeration value="superior"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:attribute>
    </xs:attributeGroup>
    <xs:element name="ciclo">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="nombre" type="xs:string"/>
                <xs:element name="familia" type="xs:string"/>
            </xs:sequence>
            <xs:attributeGroup ref="caracteristicas"/>
        </xs:complexType>
    </xs:element> 

--XML: 
<?xml version="1.0" encoding="UTF-8"?>
<ciclo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ejemploAttributeGroup.xsd" duracion="2000" grado="superior">
    <nombre>Desenvolvemento de aplicaciones web</nombre>
    <familia>IFC</familia>
</ciclo>

Utilizando un grupo de atributos deste modo podemos aumentar a lexibilidade dos esquemas e facilitar a actualización dos esquemas xa que un grupo de atributos defíne nun único lugar e pode ser referenciado en múltiples definicions e declaraciones.

Anotacións

Usanse para documentar o esquema XML e non teñen efecto na súa validación (sempre que estén ben formadas). No pueden ir en calquier parte do documento: deben estar antes ou despois dun compoñente global.

Existen dous tipos de anotacións:

  • as dirigidas a personas (documentation), que poden ter os atributos
  • source (URL con información adicional)
  • lang (idioma da documentación)
<xs:documentation source=http://www.web.com/documentacion.txt xml:lang="ES"/> 
 ... texto explicativo da documentación ...
</xs:documentation>
  • as dirigidas a programas (appinfo). Solamente teñen o atributo
  • source
<xs:appinfo source="http://www.web.com/docum.xml"/>

Valores nulos

Permiten representar valores nulos (no confundir co valor da cadea vacía). Para definir o atributo como nullable no esquema usaremos o atributo nilable asignándolle o valor “true”.

No documento XML usaríamos o atributo xsi:nil=”true” para asignarlle o valor null ó elemento.

-- Esquema 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="guarderia">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="neno" minOccurs="1" maxOccurs="50" type="tipoNeno"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="tipoNeno">
        <xs:sequence>
            <xs:element name="nome" type="xs:string"/>
            <xs:element name="idade" type="xs:unsignedByte" nillable="true"/>
        </xs:sequence>
        <xs:attribute name="numeroExpediente" type="xs:unsignedShort"/>
    </xs:complexType>
</xs:schema> 

-- Documento XML 
<?xml version="1.0" encoding="UTF-8"?>
<guarderia xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="exemploNillable.xsd">
    <neno numeroExpediente="3455">
        <nome>Nuno Cruz Vila</nome>
        <idade xsi:nil="true"></idade>
    </neno>
</guarderia>

Elementos únicos

Especifícanse por medio do elemento unique (que permitiría asignar valores nulos pero non podería haber dous elementos co valor nulo). O elemento unique consta de dous subelementos:

  • Selector: selecciona un subconxunto del elemento por medio de xpath
  • Field: dentro do subconxunto seleccionados indicamos tamén con xpath cal será o elemento ou elementos que non se poden repetir
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="axenda">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="contacto" type="tipoContacto" maxOccurs="100"/>
            </xs:sequence>
        </xs:complexType>
        <xs:unique name="nomeUnico">
            <xs:selector xpath="contacto"/>
            <xs:field xpath="nome"/>
        </xs:unique>
    </xs:element>
    <xs:complexType name="tipoContacto">
        <xs:sequence>
            <xs:element name="nome" type="xs:string"/>
            <xs:element name="telefono" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema> -- Documento XML: 
<?xml version='1.0' encoding='UTF-8' ?>
<axenda xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="exemploUnique.xsd">
    <contacto>
        <nome>Iria</nome>
        <telefono>988988982</telefono>
    </contacto>
    <contacto>
        <nome>Ana</nome>
        <telefono>982988991</telefono>
    </contacto>
</axenda>

Claves

Defínense co elemento key e teñen a mesma estrutura que unique coa diferenza de que non admiten valores nulos. Para definir una clave foránea podemos usar o elemento keyref, que nos permitirá facer referencia á clave á que apunta.

XSD 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="empresa">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="empregado" type="tipoEmpregado" maxOccurs="200"/>
                <xs:element name="departamento" type="tipoDepartamento" maxOccurs="8"/>
            </xs:sequence>
        </xs:complexType>
        <xs:key name="depUnico">
            <xs:selector xpath="departamento"/>
            <xs:field xpath="@codigo"/>
        </xs:key>
        <xs:keyref name="departamento" refer="depUnico">
            <xs:selector xpath="empregado"/>
            <xs:field xpath="departamento"/>
        </xs:keyref>
    </xs:element>
    <xs:complexType name="tipoEmpregado">
        <xs:sequence>
            <xs:element name="nombre" type="xs:string"/>
            <xs:element name="departamento" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="tipoDepartamento">
        <xs:sequence>
            <xs:element name="nombre" type="xs:string"/>
        </xs:sequence>
        <xs:attribute name="codigo" type="xs:string" use="required"/>
    </xs:complexType>
</xs:schema> 

XML 
<?xml version='1.0' encoding='UTF-8' ?>
<empresa
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ejemploKey.xsd">
    <empregado>
        <nombre>Iria</nombre>
        <departamento>IFC</departamento>
    </empregado>
    <empregado>
        <nombre>Xoel</nombre>
        <departamento>CON</departamento>
    </empregado>
    <departamento codigo="IFC">
        <nombre>Informática</nombre>
    </departamento>
    <departamento codigo="CON">
        <nombre>Contabilidade</nombre>
    </departamento>
</empresa>

En caso de indicar un valor inexistente para o código do departamento, daría unha mensaxe de erro.

Reutilización de esquemas

Existen tres formas de reutilizar declaracións realizadas nun esquema en outros esquemas que fagan uso da mesma información:

  • Incluir a definición dun esquema en outro (xs:include): neste caso os elementos deben estar no mesmo espazo de nomes (é como si estivesen todos no mesmo ficheiro). Esta opción permite reutilizar as definicións dos elementos do esquema tal como están creadas.
  • Redefinir os tipos complexos, simples, grupos ou grupos de atributos existentes nun xsd (xs:redefine). Requiere que os compoñentes externos non teñan espazo de nomes ou que estén no mesmo espazo de nomes que o esquema que os vai a redefinir.
  • Importar declaraciones realizadas nun esquema noutro esquema diferente (xs:import). Neste caso as declaracións poden pertencer a espazos de nomes diferentes.

O seguinte exemplo amosa como incluir, redefinir ou importar a definición dun tipo de dato “nomePropio” declarado nun ficheiro “definicionsComunes.xsd” que estará formado por unha letra maiúscula seguida de letras minúsculas indefinidas:

<?xml version="1.0" encoding="UTF-8"?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:simpleType name="tipoNombrePropio"> 
      <xs:restriction base="xs:string">
        <xs:pattern value="[A-ZÑÁÉÍÓÚ][a-zñáéíóú]*"/> 
      </xs:restriction> 
    </xs:simpleType>
  </xs:schema>
  • Include (ficheiro “exemploInclude.xsd”)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:include schemaLocation="definicionsComunes.xsd"/>
    <xs:complexType name="tipoNombreCompleto">
        <xs:sequence>
            <xs:element name="nombre" type="tipoNombrePropio"/>
            <xs:element name="apellido1" type="tipoNombrePropio"/>
        </xs:sequence>
    </xs:complexType>
    <xs:element name="persona" type="tipoNombreCompleto"/>
</xs:schema>
  • Redefine (fichero “exemploRedefine.xsd”):
<?xml version='1.0' encoding='UTF-8' ?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:redefine schemaLocation="exemploInclude.xsd">
        <xs:complexType name="tipoNombreCompleto">
            <xs:complexContent>
                <xs:extension base="tipoNombreCompleto">
                    <xs:sequence>
                        <xs:element name="apellido2" type="xs:string"/>
                    </xs:sequence>
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    </xs:redefine>
    <xs:element name="persona">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="nombreC" type="tipoNombreCompleto"/>
                <xs:element name="apodo" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>
  • import
<xs:schema ...>
    <xs:import namespace="A" schemaLocation="exemploInclude.xsd"/>
    <xs:import namespace="P" schemaLocation="exemploRedefine.xsd"/> . . . 
</xs:schema>

Referencias