Guía de XML Schema - Irene-Frias/1DAM GitHub Wiki

📓 Guía XML Schema

🖋️ ¿Qué es un XSD?

XML Schema (XSD - XML Schema Definition) es un lenguaje utilizado para definir la estructura, contenido y restricciones de un documento XML. Su propósito es garantizar que los datos almacenados o intercambiados en XML sigan un formato específico y sean válidos según reglas predefinidas.

A diferencia de DTD (Document Type Definition), XML Schema ofrece una sintaxis más avanzada y expresiva, ya que:

  • Está basado en XML, lo que facilita su legibilidad e integración.
  • Permite definir tipos de datos (números, fechas, booleanos, etc.).
  • Soporta estructuras complejas y reutilización de elementos.
  • Es compatible con namespaces, lo que evita conflictos entre esquemas.

🏗️ Estructura de documento XML Schema

La estructura básica de este documento se realiza con un esquema XML Schema comienza con la declaración del namespace de XSD y define los elementos y atributos permitidos en el documento XML.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
    <!-- Definición de un elemento simple -->
    <xs:element name="persona">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="nombre" type="xs:string"/>
                <xs:element name="edad" type="xs:int"/>
                <xs:element name="correo" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

Hay diferentes componentes claves de un XSD en los que se definen que son los siguientes:

  • Elementos se definen cuando un elemento puede ser simple con un solo valor o complejo, es decir con varios subelementos. Como podemos ver en el siguiente ejemplo:
<xs:element name="nombre" type="xs:string"/>
  • Tipos de datos son los definidos el tipo de datos de un elemento o atributo como pueden ser alguno de estos:

    • xs:string para texto
    • xs:int para número entero
    • xs:date para fecha)
    • xs:boolean para verdadero/falso
  • Tipos complejos estos permiten agrupar varios elementos dentro de uno principal. Como se puede ver en el siguiente ejemplo:

<xs:complexType>
    <xs:sequence>
        <xs:element name="calle" type="xs:string"/>
        <xs:element name="ciudad" type="xs:string"/>
    </xs:sequence>
</xs:complexType>
  • Secuencias xs:sequence son los que indican que los elementos hijos deben aparecer en un orden específico.
  • Atributos xs:attribute definen propiedades adicionales para los elementos.
<xs:complexType>
    <xs:sequence>
        <xs:element name="calle" type="xs:string"/>
        <xs:element name="ciudad" type="xs:string"/>
    </xs:sequence>
</xs:complexType>
  • Restrinciones xs:restriction permiten establecer reglas para los valores, como longitud, rango o valores específicos.
<xs:simpleType name="edadLimitada">
    <xs:restriction base="xs:int">
        <xs:minInclusive value="18"/>
        <xs:maxInclusive value="100"/>
    </xs:restriction>
</xs:simpleType>

Ejemplo completo con un XML válido con su XSD: Documento XML persona.xml

<?xml version="1.0" encoding="UTF-8"?>
<persona>
    <nombre>Juan Pérez</nombre>
    <edad>30</edad>
    <correo>[email protected]</correo>
</persona>

Documento esquema XSD persona.xsd

<?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="nombre" type="xs:string"/>
                <xs:element name="edad" type="xs:int"/>
                <xs:element name="correo" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

🔹 Tipos Simples en XML Schema - xs:simpleType

Los tipos simples en XSD definen valores sin estructura interna, es decir, datos que no contienen elementos secundarios o atributos. Son utilizados para restringir valores en elementos y atributos. Los tipos de datos básico proporcionan varios tipos de datos predefinidos dentro del espacio de nombres xs que puedan usar directamente en la definición de elementos y atributos.

Tipo de dato Descripción
xs:string Cadenas de texto
xs:int Números enteros
xs:decimal Números decimales
xs:boolean Valores true o flase
xs:date Fecha en formato YYYY-MM-DD
xs:time Hora en formato HH:MM:SS
xs:dateTime Fecha y hora combinadas
xs:float Números en punto flotante
xs:double Doble precisión para decimales

Ejemplos para definir algunos valores, algunos tipos son los siguientes:

  • Decimales, booleanos y fecha.
<xs:element name="precio" type="xs:decimal"/>
<xs:element name="activo" type="xs:boolean"/>
<xs:element name="fechaNacimiento" type="xs:date"/>
  • Restringido, permitiendo limitar el rango de valores aceptados.
<xs:simpleType name="edadLimitada">
    <xs:restriction base="xs:int">
        <xs:minInclusive value="18"/>
        <xs:maxInclusive value="100"/>
    </xs:restriction>
</xs:simpleType>
  • Enumeración, permitiendo uno de los valores especificados en ella.
<xs:simpleType name="tipoSangre">
    <xs:restriction base="xs:string">
        <xs:enumeration value="A+"/>
        <xs:enumeration value="A-"/>
        <xs:enumeration value="B+"/>
        <xs:enumeration value="B-"/>
        <xs:enumeration value="O+"/>
        <xs:enumeration value="O-"/>
        <xs:enumeration value="AB+"/>
        <xs:enumeration value="AB-"/>
    </xs:restriction>
</xs:simpleType>
  • Lista, permitiendo definir los elementos que contengan los valores separados por espacios.
<xs:simpleType name="coloresPermitidos">
    <xs:list itemType="xs:string"/>
</xs:simpleType>

🔄 Facets en XML Schema

Las facets en XML Schema son restricciones que se aplican a los tipos simples para definir reglas más específicas sobre sus valores. Estas restricciones permiten limitar o modificar cómo se interpretan los datos dentro de un esquema XML.

  • Control de la longitud permiten limitar la cantidad de caracteres que un elemento pueda contener.
    • length limita la cadena a que sea una longitud exacta
    • minLength limita la cadena a que sea una longitud mínima
    • maxLength limita la cadena a que sea una longitud máxima
<xs:simpleType name="codigoPostal">
  <xs:restriction base="xs:string">
    <xs:length value="5"/>
  </xs:restriction>
</xs:simpleType>
  • Patrones específicos permiten usar expresiones regulares para definir el formato que debe seguir el valor.
<xs:simpleType name="matricula">
  <xs:restriction base="xs:string">
    <xs:pattern value="[A-Z]{3}-\d{4}"/>
  </xs:restriction>
</xs:simpleType>
  • Manipulación con números permiten establecer valores máximos y mínimos.
    • minInclusive permite una longitud mínima (incluyendo el valor)
    • maxInclusive permite una longitud máxima (incluyendo el valor)
    • minExclusive permite una longitud mínima (excluyendo el valor)
    • maxExclusive permite una longitud máxima (excluyendo el valor)
<xs:simpleType name="edad">
  <xs:restriction base="xs:int">
    <xs:minInclusive value="18"/>
    <xs:maxInclusive value="99"/>
  </xs:restriction>
</xs:simpleType>
  • Enumeraciones limita los valores posibles a una lista predefinida.
<xs:simpleType name="diaSemana">
  <xs:restriction base="xs:string">
    <xs:enumeration value="Lunes"/>
    <xs:enumeration value="Martes"/>
    <xs:enumeration value="Miércoles"/>
    <xs:enumeration value="Jueves"/>
    <xs:enumeration value="Viernes"/>
  </xs:restriction>
</xs:simpleType>
  • Manejo de espacios en blanco definiendo el comportamiento de los espacios en blanco procesados.
    • preserve mantiene todo igual, es decir no cambia
    • replace reemplaza tabuladores y saltos de línea por espacios
    • collapse elimina múltiples espacios y los reduce a uno solo
<xs:simpleType name="textoNormalizado">
  <xs:restriction base="xs:string">
    <xs:whiteSpace value="collapse"/>
  </xs:restriction>
</xs:simpleType>

📌 Especificación local del tipo elemento

Cuando al especificas un elemento directamente dentro de otro, sin crear ningún tipo con nombre estas definiendo el tipo de especificación local. Esto es útil cuando el tipo solo se usa una vez.

En XML Schema puedes definir el tipo de un elemento de dos formas:

  • Localmente: El tipo se define dentro del propio elemento.
  • Globalmente: El tipo se define de forma separada y se reutiliza en varios lugares.
<xs:element name="telefono">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:pattern value="\d{9}"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

Estos tipos locales se usan cuando se necesitan en un único lugar. Otras veces son utilizados para mantener la lógica cerca del dato y cuando no se necesita reutilización en otros elementos.


🧬 Tipos no atómicos

Son los que permiten representar más de un valor en un solo elemento en el XML. Hay des formas principales en la que puede representarse:

  • Listas permite que un elemento contenga varios valores del mismo tipo, separados por espacios.
<!-- De manera global -->
<xs:simpleType name="listaDeEnteros">
  <xs:list itemType="xs:int"/>
</xs:simpleType>

<!-- De manera local -->
<xs:element name="codigos">
  <xs:simpleType>
    <xs:list itemType="xs:string"/>
  </xs:simpleType>
</xs:element>
  • Uniones permite que un elemento tenga un valor que puede ser de uno entre varios tipos posibles.
<xs:simpleType name="enteroOEspecial">
  <xs:union memberTypes="xs:int palabraClave"/>
</xs:simpleType>

<xs:simpleType name="palabraClave">
  <xs:restriction base="xs:string">
    <xs:enumeration value="N/A"/>
    <xs:enumeration value="Desconocido"/>
  </xs:restriction>
</xs:simpleType>

🌍 Declaración de elementos de tipos simples globales

La declaración de los tipos simples de manera global fuera de cualquier elemento se puede reutilizar en distintos puntos del esquema. Estos tipos son personalizados definiendo con un nombre y aplicándolos a muchos elementos.

<xs:simpleType name="dniTipo">
  <xs:restriction base="xs:string">
    <xs:pattern value="\d{8}[A-Z]"/>
  </xs:restriction>
</xs:simpleType>

<xs:element name="dni" type="dniTipo"/>
<xs:element name="representanteDni" type="dniTipo"/>

Estos elementos se suelen aplicar en un patrón a varios elementos. Se puede mantener la consistencia y evitar la repetición de dichos elementos. De esta forma puede crearse un esquema menos complejo o extenso.

Tipo de dato Tipo Global Tipo Local
Definición Fuera del elemento Dentro del elemento
Reutilización No
Legibilidad Se centraliza en un solo lugar Más contexto en el lugar usado
Modularidad Mejora la organización No reutilizable fácilmente

Los valores por defecto se pueden definir como un elemento o atributo, si no se incluye en XML.


📚 Elementos de tipo complejo

Un elemento de tipo complejo es aquel que puede contener otros elementos o atributos. Mientras que los tipos simples son sólo datos (texto, número, fecha), los tipos complejos permiten estructuras. Como se puede ver en el ejemplo:

<!-- Fichero XML --> 
<persona>
  <nombre>Juan</nombre>
  <edad>30</edad>
</persona>
<!-- Fichero XSD --> 
<xs:element name="persona">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="nombre" type="xs:string"/>
      <xs:element name="edad" type="xs:int"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

El contenido de este tipo se puede organizar de tres formas principales dentro de un tipo complejo:

  • xs:sequence los elementos deben aparecer en el orden exacto en el que se definen. En el orden especificado, como podemos ver en el ejemplo. En el fichero XML se pondría primero la etiqueta nombre y luego apellido.
<xs:sequence>
  <xs:element name="nombre"/>
  <xs:element name="apellido"/>
</xs:sequence>
  • xs:all todos los elementos pueden aparecer en cualquier orden, pero cada uno como máximo una vez. En este caso no hay orden estipulado, esto quiere decir que podrá ponerse en el orden que se quiera. En el fichero XML se podría poner primero la etiqueta ciudad y luego calle o al revés.
<xs:all>
  <xs:element name="calle"/>
  <xs:element name="ciudad"/>
</xs:all>
  • xs:choice se elige un solo elemento entre varios elementos posibles. En el fichero XML se podría poner solamente uno como etiqueta telefono o email.
<xs:choice>
  <xs:element name="telefono"/>
  <xs:element name="email"/>
</xs:choice>

Los grupos de contenido permiten reutilizar combinaciones de elementos. Cada elemento puede tener restricciones:

  • minOccurs el número mínimo de apariciones.
  • maxOccurs el número máximo de apariciones. En el siguiente ejemplo, podemos ver que puede no aparecer o puede aparecer hasta 3 veces.
<xs:element name="telefono" type="xs:string" minOccurs="0" maxOccurs="3"/>

Cuando declaramos los elementos de tipo complejo de forma global (fuera de los elementos) para poder reutilizarlo.

<xs:complexType name="direccion">
  <xs:sequence>
    <xs:element name="calle" type="xs:string"/>
    <xs:element name="ciudad" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

<xs:element name="envio" type="direccion"/>
<xs:element name="facturacion" type="direccion"/>

Además también se permite que un elemento contenga texto y otros subelementos al mismo tiempo.

<!-- Fichero XML --> 
<parrafo>Esto es un <negrita>ejemplo</negrita> de contenido mixto.</parrafo>
<!-- Fichero XSD --> 
<xs:complexType mixed="true">
  <xs:sequence>
    <xs:element name="negrita" type="xs:string"/>
  </xs:sequence>
</xs:complexType>

También se pueden agregar atributos, restricciones,... y tener un tipo totalmente modular.


📝 Atributos

Los atributos son como propiedades que se agregan a los elementos XML. Se colocan dentro de la etiqueta de apertura del elemento y proporcionan información adicional. En este ejemplo que vemos, el atributo genero sería el elemento de persona.

<persona genero="masculino">Juan</persona>

También puedes tener elementos que no contienen texto ni otros elementos, solo atributos:

<entrada activa="true"/>

Si un elemento tiene otros subelementos, aún puedes agregarle atributos. Lo haces dentro de un xs:complexType con xs:sequence y luego xs:attribute.

<xs:complexType>
  <xs:sequence>
    <xs:element name="nombre" type="xs:string"/>
  </xs:sequence>
  <xs:attribute name="id" type="xs:string" use="required"/>
</xs:complexType>

Si el elemento solo contiene texto pero también necesitas un atributo, puedes usar xs:simpleContent con xs:extension.

<xs:complexType>
  <xs:simpleContent>
    <xs:extension base="xs:string">
      <xs:attribute name="formato" type="xs:string"/>
    </xs:extension>
  </xs:simpleContent>
</xs:complexType>

Puedes limitar lo que se permite como valor de un atributo usando restricciones como pattern, enumeration,... Como podemos ver en el ejemplo, el atributo estadosolo puede tener varios valores"activo"o"inactivo"`

<xs:attribute name="estado">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="activo"/>
      <xs:enumeration value="inactivo"/>
    </xs:restriction>
  </xs:simpleType>
</xs:attribute>

Si el atributo no se escribe, se usará un valor predeterminado automáticamente (default). Si nos basamos en el ejemplo que viene a continuación, si en el XML no se escribe pais, el valor por defecto será "España".

<xs:attribute name="pais" type="xs:string" default="España"/>

Cuando usas fixed en un atributo, estás diciendo que ese atributo siempre debe tener exactamente ese valor. No puede cambiarse, ni omitirse (si el elemento lo incluye).

<xs:attribute name="tipo" type="xs:string" fixed="cliente"/>

Si quieres que un atributo sea obligatorio y que siempre esté presente en el XML, debes usar required

<xs:attribute name="id" type="xs:string" use="required"/>

📜 Plantillas base de estructura

Las estructuras básicas para no confundirte con cierres de etiquetas o elementos:

1. Elemento simple

<xs:element name="nombre" type="xs:string"/>

2. Elemento con restricción

  • Con patrón (pattern)
<xs:element name="dni">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:pattern value="\d{8}[A-Z]"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>
  • Con rango numérico
<xs:element name="edad">
  <xs:simpleType>
    <xs:restriction base="xs:int">
      <xs:minInclusive value="0"/>
      <xs:maxInclusive value="120"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>
  • Con enumeración
<xs:element name="nivel">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="básico"/>
      <xs:enumeration value="intermedio"/>
      <xs:enumeration value="avanzado"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>

3. Elemento complejo con subelementos

  • Con orden específico (xs:sequence)
<xs:element name="direccion">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="calle" type="xs:string"/>
      <xs:element name="ciudad" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
  • En cualquier orden (xs:all)
<xs:element name="datos">
  <xs:complexType>
    <xs:all>
      <xs:element name="nombre" type="xs:string"/>
      <xs:element name="apellido" type="xs:string"/>
    </xs:all>
  </xs:complexType>
</xs:element>
  • Uno u otro (xs:choice)
<xs:element name="contacto">
  <xs:complexType>
    <xs:choice>
      <xs:element name="telefono" type="xs:string"/>
      <xs:element name="email" type="xs:string"/>
    </xs:choice>
  </xs:complexType>
</xs:element>

4. Elementos con atributos

  • Solo atributos
<xs:element name="usuario">
  <xs:complexType>
    <xs:attribute name="id" type="xs:string" use="required"/>
  </xs:complexType>
</xs:element>
  • Texto + atributos (simpleContent)
<xs:element name="comentario">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="autor" type="xs:string"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>

5. Listas de valores

<xs:element name="hobbies">
  <xs:simpleType>
    <xs:list itemType="xs:string"/>
  </xs:simpleType>
</xs:element>

6. Contenido mixto (texto + subelementos)

<xs:element name="parrafo">
  <xs:complexType mixed="true">
    <xs:sequence>
      <xs:element name="negrita" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

7. Tipo complejo global reutilizable

<xs:complexType name="personaTipo">
  <xs:sequence>
    <xs:element name="nombre" type="xs:string"/>
    <xs:element name="edad" type="xs:int"/>
  </xs:sequence>
</xs:complexType>

<xs:element name="cliente" type="personaTipo"/>
<xs:element name="empleado" type="personaTipo"/>
⚠️ **GitHub.com Fallback** ⚠️