[Apuntes] Lenguajes de marcas: DTD y XML Schema

Miguel Menéndez

DTD y XML Schema.

DTD

Una DTD es un documento SGML que incluye las reglas sintácticas para un tipo de documento específico. Incluye los elementos que se permiten y sus atributos, así como reglas que afectan a la anidación de los primeros y a los valores de los segundos. Contrastando un documento con su DTD se puede comprobar si éste es válido o no.

DTD no es XML.

Vincular una DTD a un documento XML

<!DOCTYPE nombreElementoRaíz [declaraciones]>
<!DOCTYPE nombreElementoRaíz SYSTEM "nombreArchivo.dtd">
<!DOCTYPE nombreElementoRaíz PUBLIC "FPI" "URI">

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
          "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

Estructura de una DTD

Los contenidos que pueden incluirse en un documento XML están definidos en la DTD utilizando cuatro posibles términos: ELEMENT (para declarar elementos), ATTLIST (para declarar atributos), ENTITY (para declarar contenidos reutilizables) y NOTATION.

ELEMENT

<!ELEMENT nombreElemento especificacionesContenido …>
  1. Elemento tipo contenido de elemento: Ementos que sólo tienen permitido contener a otros elementos:
<!ELEMENT A (B, C)>

El elemento A contiene al elemento B seguido del elemento C (en ese orden). La coma indica que necesariamente deben aparecer en ese orden.

  1. Elemento tipo contenido de texto: Elementos que solo pueden contener datos textuales (cadenas de carácteres). También permite que el elemento quede vacío:
<!ELEMENT A (#PCDATA)>

El elemento A contiene datos textuales.

  1. Elemento tipo mixto: Elementos que pueden contener cualquier cosa (datos textuales, elementos, ambos o nada):
<!ELEMENT A ANY>
<!-- o -->
<!ELEMENT A (#PCDATA | hijo1 | hijo2)*>

El elemento A contiene cualquier cosa (datos textuales, elementos, nada). La barra vertical (|) significa que el elemento contiene sólo uno de los elementos definidos a uno y otro lado de la barra.

  1. Elemento tipo elemento vacío: Elementos que carecen de cualquier tipo de contenido. Implica que ese elemento tendrá la forma <etiqueta /> dentro del documento:
<!ELEMENT hr EMPTY>

El elemento hr no contiene nada.

Los operadores (, |) pueden anidarse usando paréntesis:

<!ELEMENT datosPersonales (nombre, dirección, (teléfono | mail))>

Los elementos que contienen datos textuales (#PCDATA), nada (EMPTY) o cualquier cosa (ANY) son elementos terminales.

Operadores de cardinalidad o frecuencia

  • Operador ? indica que el elemento es opcional, es decir, puede aparecer o no, pero de aparecer puede hacerlo solo una vez (0 o 1 veces).
  • Operador + indica que el elemento debe aparecer por lo menos una vez pero puede hacerlo n veces. (1 o n veces).
  • Operador * indica que el elemento en cuestión también es opcional pero de aparecer lo puede hacer n veces. (0 o n veces).
<!ELEMENT datosPersonales (nombre+, dirección?, (teléfono | mail)*)>

Si no se usa ningún cardinal, el cardinal por defecto es 1.

ATTLIST

Los elementos pueden tener cero, uno o varios atributos. La especificación de atributos sólo puede aparecer dentro de la etiqueta de apertura.

<!ATTLIST nombreElemento nombreAtributo tipo indicadores
                         nombreAtributo tipo indicadores
                         … >
  1. Atributo tipo CDATA: El valor del atributo será del tipo cadena de carácteres (que no contenga >, <, &, ‘, “):
<!ATTLIST domicilio ciudad CDATA #IMPLIED>
Sería válido <domicilio ciudad="Uviéu"></domicilio>.
  1. Atributo tipo enumeración: Permite establecer un número limitado de valores posibles para un determinado atributo. Los valores aparecen separados por una barra vertical (|), no van entrecomillados y son sensibles al uso de mayúsculas y minúsculas. No debe usarse en combinación con #REQUIRED, #IMPLIED ni #FIXED:
<!ATTLIST semáforo color (rojo | amarillo | verde) "rojo">

El atributo color puede incluir uno y solo uno de estos valores permitidos. El valor por defecto de este atributo se ha establecido como “rojo”.

  1. Atributo tipo ID: El valor del atributo debe ser único en todo el documento. Ningún elemento puede tener más de un atributo ID. Un atributo ID sólo puede ser #IMPLIED o #REQUIRED pero nunca #FIXED. El valor de un ID debe ser un nombre XML válido (formado por letras, números, guiones y puntos, y debe empezar por letra o subrayado):
<!ATTLIST empleado identificador ID #REQUIRED>

Sería válido: <empleado identificador="AA_125">La mujer araña</empleado>.

  1. Atributo tipo IDREF: El valor del atributo es el valor del ID de un elemento relacionado que se encuentre en el mismo documento XML:
<!ATTLIST fechaIngreso empleado IDREF #REQUIRED>

Sería válido: <fechaIngreso empleado="AA_125">12/5/2000</fechaIngreso>.

  1. Atributo tipo IDREFS: El valor del atributo es una lista de los valores de los ID de los elementos que queremos relacionar separados por un espacio en blanco. Sólo se pueden relacionar ID presentes en el mismo documento:
<!ELEMENT equipo EMPTY>
<!ATTLIST equipo miembros IDREFS #REQUIRED>

Sería válido: <equipo miembros="AA_125 AB_320 AA_210 AA_012" />.

  1. Atributo tipo NMTOKEN: El valor del atributo debe ser una cadena compuesta por los carácteres permitidos para nombres XML válidos (sólo letras, números, guiones y puntos, sin espacios en blanco) pero no hay obligación de que empiece por letra o subrayado:
<!ELEMENT río (nombre)>
<!ATTLIST río país NMTOKEN #REQUIRED>

No sería válido: <río país="Estados Unidos"><nombre>Mississippi</nombre></río>.

Sí sería válido: <río país="USA"><nombre>Mississippi</nombre></río>.

  1. Atributo tipo NMTOKENS: El valor del atributo podrá contener un número n de valores del tipo NMTOKEN separados entre sí por un espacio en blanco:
<!ELEMENT categoría (#PCDATA)>
<!ATTLIST categoría tipo NMTOKENS #REQUIRED>

Sería válido: <categoría tipo="director jefeCompras 1:contratoFijo" />.

  1. Atributos tipo ENTITY y ENTITIES: El valor del atributo es una entidad o una lista de n entidades:
<!NOTATION gif SYSTEM "image/gif">
<!ENTITY gráficoVentas_1 SYSTEM "grafico_1.gif" NDATA gif>
<!ATTLIST resultadoVentas gráfico ENTITY #IMPLIED>

Sería válido: <resultadoVentas gráfico="gráficoVentas_1"></resultadoVentas>.

  1. Atributo tipo NOTATION: El valor del atributo es alguna notación definida en la DTD:
<!NOTATION gif SYSTEM "image/gif">
<!NOTATION jpg SYSTEM "image/jpeg">
<!ATTLIST foto tipo NOTATION ( gif | jpg ) #IMPLIED>

Sería válido: <foto tipo="jpg"></foto>.

Ocurrencia de los atributos (indicadores)

#REQUIRED: El atributo es obligatorio aunque no se especifica un valor concreto para el mismo. Debe estar presente en el documento XML, aunque puede aparecer vacío:

<!ATTLIST img alt CDATA #REQUIRED>

Sería válido: <img alt=""></img>.

#IMPLIED: Define el atributo como opcional. En caso de que en el documento XML el elemento cuente con el atributo, el valor será el especificado. En caso contrario, su valor será indefinido:

<!ATTLIST img width CDATA #IMPLIED>

Sería válido: <img width="256"></img> <img width=""></img> <img></img>.

#FIXED: Este indicador hace que el valor del atributo se tome siempre como valor fijo, aparezca el atributo en el elemento o no. Si el atributo no aparece en el elemento, el procesador asume el que le hayamos asignado en esta declaración (inmediatamente después y entrecomillado). Si aparece el atributo con un valor diferente a éste se producirá un error de validación:

<!ATTLIST html xmlns CDATA #FIXED 'http://www.w3.org/1999/xhtml'>

Valor por defecto (predefinido): En ese caso, si no definimos un valor para el atributo, el procesador tomará el que le hemos asignado como su valor por defecto:

<!ATTLIST curso color CDATA "azul">

Sería válido: <curso color="azul"></curso> <curso color="rojo"></curso> <curso></curso> … En el último caso, el parser asignará el valor azul para ese atributo.

RECUERDA: Es obligatorio utilizar alguno de los indicadores #REQUIRED, #IMPLIED, #FIXED o valor por defecto.

ENTITY

Las entidades permiten definir las constantes de los documentos XML.

  • Todas las entidades se declaran en una DTD y se referencian desde documentos XML o, en el caso de las paramétricas, desde las DTD.
  • Las entidades internas obtienen su texto de sustitución del interior de la DTD, el texto de sustitución está especificado en la declaración de la entidad.
  • Las entidades externas obtienen su texto de sustitución de un archivo externo.

Hay diferentes tipos de entidades y su sintaxis varía en función del tipo. Así, tenemos las entidades predefinidas que se referencian en documentos XML, las entidades generales procesadas (internas o externas) que se referencian en documentos XML y las entidades paramétricas (internas o externas) que se referencian en las DTD.

Entidades predefinidas

&lt; &gt; &amp; &quot; &apos; (excepto dentro de secciones CDATA).

Entidades generales procesadas

Son aquellas cuyo contenido es XML y deben ser procesadas por el parser. Se crean en la DTD y se sustituyen por su valor (se referencian) en el documento XML. El valor de una entidad procesada es conocido como contenido de reemplazo y puede ser texto o código XML. Una vez efectuado el reemplazo de la referencia a la entidad por su contenido, este contenido pasa a ser parte del documento y es analizado por el procesador como el resto del documento.

Una entidad general procesada interna se declara en la DTD:

<!ENTITY nombreEntidad "contenido de reemplazo">

Y se referencia en el documento XML:

<elemento>&nombreEntidad;</elemento>

Ejemplo:

<!-- En la DTD: -->
<!ENTITY situacion "Calle de Estrasburgo">

<!-- En el XML: -->
<dirección>
  <número>172</número>
  <calle>&situacion;</calle>
  <población>Buenos Aires</población>
</dirección>

La forma de declarar en la DTD una entidad general procesada externa privada (ubicada en nuestro sistema) es:

<!ENTITY nombreEntidad SYSTEM "URI">

Ejemplo:

<!-- En el archivo autores.txt: -->
Juan Manuel y José Ramón

<!-- En el XML: -->
<?xml version="1.0" ?>
<!DOCTYPE escritores [
  <!ELEMENT escritores (#PCDATA)>
  <!ENTITY autores SYSTEM "autores.txt">
]>
<escritores>&autores;</escritores>

La forma de declarar en la DTD una entidad general procesada externa pública (de acceso público) es:

<!ENTITY nombreEntidad PUBLIC "identificador público formal" "URI">

Ejemplo:

<!-- En el archivo escritor.txt: -->
Miguel de Cervantes Saavedra

<!-- En el XML: -->
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE textos [
  <!ELEMENT textos (texto)+>
  <!ELEMENT texto (#PCDATA)>
  <!ENTITY escritor PUBLIC "-//W3C//TEXT escritor//EN"
                           "http://www.cc.com/dtd/escritor.txt">
]>
<textos>
  <texto>El Quijote fue escrito por &escritor;.</texto>
</textos>
Entidades paramétricas

Se crean en la DTD y se referencian en la propia DTD. Para que funcionen, la DTD debe estar definida en un archivo externo. La sintaxis es igual que la de las entidades generales pero al declarar la entidad hay que poner delante del nombre de la entidad el carácter % seguido de un espacio en blanco. Y al referenciarla se antepone al nombre de la entidad el carácter % sin espacio en blanco.

La forma de declarar en la DTD una entidad paramétrica interna es:

<!ENTITY % nombreEntidad "contenido de reemplazo">

Ejemplo:

<!-- Se declara en la DTD: -->
<!ENTITY % otrosValores "edad CDATA #IMPLIED
                         peso CDATA #IMPLIED
                         altura CDATA #REQUIRED">

<!-- Se referencia, también en la DTD: -->
<!ATTLIST persona nombre CDATA #REQUIRED %otrosValores;>

La forma de declarar en la DTD una entidad paramétrica externa privada (ubicada en nuestro sistema) es:

<!ENTITY % nombreEntidad SYSTEM "URI">

Ejemplo:

<!-- En el archivo fechainiciofin.ent: -->
<!ENTITY % díasMes "1|2|3|4|5|10|19|20|21|22|28|29|30|31">
<!ENTITY % mesesAño "enero|febrero|marzo|junio|julio|agosto|septiembre"> <!ENTITY % próximosAños "2006 | 2007 | 2008 | 2009 | 2010">

<!-- Se declara en la DTD: -->
<!ENTITY % fechaInicioFin SYSTEM "fechainiciofin.ent">

<!-- Se referencia, también en la DTD: -->
%fechaInicioFin;
<!ELEMENT curso (descripción, fechaInicio, fechaFin)>
<!ELEMENT descripción (#PCDATA)>
<!ELEMENT fechaInicio EMPTY>
<!ATTLIST fechaInicio
          día (%díasMes;) #REQUIRED
          mes (%mesesAño;) #REQUIRED
          anio (%próximosAños;) #REQUIRED>
<!ELEMENT fechaFin EMPTY>
<!ATTLIST fechaFin
          día (%díasMes;) #REQUIRED
          mes (%mesesAño;) #REQUIRED
          año (%próximosAños;) #REQUIRED>

La forma de declarar en la DTD una entidad paramétrica externa pública (de acceso público) es:

<!ENTITY % nombreEntidad PUBLIC "identificador público formal" "URI">

Ejemplo:

<!-- En el archivo xhtml-lat1.ent: -->
<!ENTITY Aacute "&#193;">
<!ENTITY nbsp "&#160;">
...

<!-- Se declara en la DTD: -->
<!ENTITY % HTMLlat1 PUBLIC "-//W3C//ENTITIES Latin 1 for XHTML//EN"
                           "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">

<!-- Se referencia, también en la DTD: -->
%HTMLlat1;
Secciones condicionales

En ocasiones puede resultar útil ocultar algunas partes de la declaración de la DTD o incluir o excluir reglas en la DTD en función de condiciones. Sólo se puede ubicar en DTD externas. Su uso tiene sentido al combinarlas con referencias a entidades paramétricas. Las secciones condicionales son INCLUDE e IGNORE, y permitirán respectivamente, incluir o ignorar secciones de declaraciones dentro de una DTD:

<![INCLUDE[declaraciones visibles]]>
<!-- Ejemplo: -->
<![INCLUDE[<!ELEMENT descripción (#PCDATA)]]>

<![IGNORE[declaraciones a ocultar]]>
<!-- Ejemplo: -->
<![IGNORE[<!ELEMENT contraseña (#PCDATA)]]>

Ejemplo:

<!ENTITY % largo "INCLUDE">
<!ENTITY % corto "IGNORE">

<[%largo;[<!ELEMENT libro (comentario+, titulo, cuerpo, anexos?)>]]>
<[%corto;[<!ELEMENT libro (titulo, cuerpo, anexos?)>]]>

En este caso el documento XML admite uno o varios elementos comentario como elementos hijos de libro. Para que el elemento libro no admita como hijo el elemento comentario basta con modificar la asociación de valores de %corto a INCLUDE y de %largo a IGNORE:

<!ENTITY % corto "INCLUDE">
<!ENTITY % largo "IGNORE">

XML Schema (XSD)

XSD es XML.

Vincular una XSD a un documento XML

En XML Schema las declaraciones del esquema siempre se encuentran en un documento externo.

En el documento XML:

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

En el esquema XML:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">
  [subelementos]
</xsd:schema>

Estructura de una SXD

El esquema XML presenta dos tipos de definiciones de componentes: Simples y complejos.

  • Componentes simples sólo contienen datos textuales (cadenas de texto, números, fechas, etc.).
  • Componentes complejos contienen subelementos o tienen atributos.

Los atributos siempre son componentes simples.

Cuando se declaran los elementos y los atributos en el esquema debe especificarse para cada uno de ellos el tipo de dato, tanto si es simple como complejo.

ELEMENT

<element name="nombreElemento" type="tipoElemento" />

ATTRIBUTE

<attribute name="nombreAtributo" type="tipoAtributo" [use=""] />

Modelos de construcción del esquema

  • Diseño plano
  • Diseño con tipos con nombres reutilizables (más abajo)
  • Diseño anidado (de muñecas rusas)

Se siga el modelo de construcción que se siga, el orden en que se declaran los elementos en un esquema no es significativo ni afecta al funcionamiento del mismo.

Diseño plano

  • Los elementos simples (terminales) y los atributos se declaran en primer lugar.
  • La declaración de los elementos complejos aparece a continuación, en ella se detallan los subelementos de los que se compone el elemento complejo, relacionándolos con los declarados anteriormente (con el atributo ref).
  • El último elemento complejo que se define es elemento raíz.

Cardinalidad de los elementos

La cardinalidad define el número de veces que puede aparecer un elemento.

  • Atributo minOccurs: Indica el número mínimo de veces que puede aparecer un elemento. El valor 0 para el atributo minOccurs supone que dicho elemento es opcional, puede aparecer o no dentro del documento. El valor 1 supone que debe aparecer como mínimo una vez. El valor de este atributo puede ser cualquier entero positivo, 112 por ejemplo.
  • Atributo maxOccurs: Indica el número máximo de veces que puede aparecer un elemento. Su valor también puede ser un entero positivo o el término unbounded, sin límite, para indicar que no existe un número máximo de ocurrencias.

El valor por defecto de ambos atributos es 1. Si ambos atributos son omitidos, el elemento debe aparecer exactamente una vez.

Ocurrencia de los atributos

Los atributos definidos para los elementos XML pueden aparecer una vez o ninguna, pero ningún otro número de veces.

  • required: Significa requerido, obligatorio.
  • optional: Significa opcional.
  • prohibited: Significa que el atributo no debe aparecer.

El valor por defecto del atributo use es optional.

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

Valores por defecto y valores fijos en elementos simples y atributos

<xs:element name="precio" type="xs:decimal" default="5" />
<xs:attribute name="moneda" type="xs:NMTOKEN" default="euro" />

Los valores por defecto de los atributos se aplican cuando éstos no están presentes, y los valores por defecto de los elementos se aplican cuando éstos están vacíos.

<xs:element name="precio" type="xs:decimal" fixed="5" />
<xs:attribute name="moneda" type="xs:NMTOKEN" fixed="euro" />

El elemento precio debe aparecer en el documento XML con el valor 5 y el atributo moneda, si aparece, debe contener el valor “euro”.

Los conceptos de un valor fijo y de un valor por defecto son mutuamente excluyentes, y por lo tanto constituye un error que una declaración contenga ambos atributos fixed y default.

Elementos
Atributo Valores Observaciones
minOccurs 0 a n Por defecto: 1
maxOccurs 0 a n Por defecto: 1
unbounded Número ilimitado de veces
fixed valor El contenido del elemento debe ser el valor especificado
default valor Si el elemento no tiene contenido su contenido es el valor por defecto. Si tiene contenido no se aplica el valor por defecto
Atributos
Atributo Valores Observaciones
use optional Valor por defecto. El atributo puede aparecer o no.
required El atributo debe aparecer.
prohibited El atributo no debe aparecer.
fixed valor Si el atributo aparece, el valor debe ser el valor fijado.
default valor Si el atributo no aparece, su valor es el valor por defecto. Si el atributo tiene valor, su valor es el que tiene.

Tipos de datos

  • Predefinidos: Son los que vienen integrados en la especificación de los Esquemas XML. Existen 44 tipos predefinidos (string, byte, integer, decimal…). Ver la otra chuleta.
  • Construidos: Son tipos generados por el usuario basándose en un tipo predefinido o en un tipo previamente construido.

Diseño con tipos con nombres reutilizables

Se definen tipos de datos simples o complejos a los que se identifica con un nombre (forman plantillas). Al declarar elementos y atributos, se indica que son de alguno de los tipos con nombre previamente definidos.

Tipos de datos simples
<simpleType name="nombreTipo">
  [restricciones]
</simpleType>

<!-- Ejemplo: -->
<xs:simpleType name="nombreType">
  <xs:restriction base="xs:string">
    <xs:maxLength value="32" />
  </xs:restriction>
</xs:simpleType>
Otro tipo simple no atómico: Lista

Los tipos lista están compuestos de secuencias de tipos atómicos.

se pueden crear nuevos tipos de listas por derivación de los tipos atómicos existentes. No está permitido crear tipos de lista partiendo de tipos de lista existentes, ni de tipos complejos.

<!-- Recordemos cómo era la definición de este tipo -->
<xs:simpleType name="miEntero">
  <xs:restriction base="xs:integer">
    <xs:minInclusive value="10000" />
    <xs:maxInclusive value="99999" />
  </xs:restriction>
</xs:simpleType>

<!-- Aquí definimos la lista -->
<xs:simpleType name="listaDeMisEnteros">
  <xs:list itemType="miEntero" />
</xs:simpleType>

<!-- Definimos el elemento -->
<xs:element name="misEnteros" type="listaDeMisEnteros" />
Otro tipo simple no atómico: Unión

Un tipo unión es un tipo de dato creado a partir de otros tipos de datos que se declaran en el atributo memberTypes, generalmente tipos atómicos o tipos lista. Un valor válido para un tipo unión sería aquel que pertenece a alguno de los tipos que forman la unión.

<xs:simpleType name="europaCod">
  <xs:union memberTypes="listaPaises listaDeMisEnteros" />
</xs:simpleType>

<!-- Definimos el elemento -->
<xs:element name="codigosEur" type="europaCod" />
Tipos de datos complejos
<complexType name="nombreTipo">
  [composición]
</complexType>

<!-- Ejemplo: -->
<xs:complexType name="articuloType">
  <xs:sequence>
    <xs:element name="titulo" type="nombreType" />
  </xs:sequence>
</xs:complexType>
Tipo de dato complejo: Secuencia

Los elementos aparecen unos detrás de otros en un orden determinado. Se declara con el compositor <xs:sequence>. Los elementos de la secuencia puede aparecer un número variable de veces, configurable con los atributos minOccurs y maxOccurs (ambos valen 1 por defecto).

<xs:element name="articulo" >
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="titulo" />
      <xs:element ref="autor" minOccurs="0" maxOccurs="unbounded" />
      <xs:element ref="numeropalabras" />
      <xs:element ref="texto" />
    </xs:sequence>
  </xs:complexType>
</xs:element>
Tipo de dato complejo: Compositor choice

El compositor <xs:choice> permite declarar los elementos que aparecen como alternativa unos de los otros. Sólo se elige uno. El elemento elegido puede aparecer un número variable de veces, configurable con los atributos minOccurs y maxOccurs (ambos valen 1 por defecto).

<xs:element name="libro">
  <xs:complexType>
    <xs:sequence>
      <xs:choice>
        <xs:element name="prologo" type="xs:string" />
        <xs:element name="prefacio" type="xs:string" />
        <xs:element name="introduccion" type="xs:string" />
      </xs:choice>
      <xs:element name="titulo" type="xs:string"/>
      ...
    </xs:sequence>
  </xs:complexType>
</xs:element>
Tipo de dato complejo: Compositor all

Existe una tercera opción para restringir los elementos de un grupo, se trata del compositor <xs:all>. Este compositor establece que todos los elementos de un grupo all pueden aparecer una vez o ninguna, y pueden aparecer en cualquier orden.

El Esquema XML establece que un grupo all debe aparecer como hijo único en el nivel más alto del modelo de contenido. Más aún, los hijos de all deben ser todos elementos individuales, no grupos, y ningún elemento en el modelo debe aparecer más de una vez, es decir, los valores permitidos de minOccurs y maxOccurs son 0 y 1 (1 por defecto).

<xs:element name="hojaPedido">
  <xs:complexType>
    <xs:all>
      <xs:element name="enviarA" type="direccionEEUU" />
      <xs:element name="facturarA" type="direccionEEUU" />
      <xs:element name="comentario" type="xs:string" minOccurs="0" />
      <xs:element name="elementos" type="Elementos" />
    </xs:all>
    <xs:attribute name="fechaPedido" type="xs:date" />
  </xs:complexType>
</xs:element>

Grupos de elementos

<!-- Definición de un grupo de elementos -->
<xs:group name="infoRevista">
  <xs:sequence>
    <xs:element name="nombre" type="xs:string"/>
    <xs:element name="fechaSalida" type="xs:string"/>
  </xs:sequence>
</xs:group>

Grupos de atributos

<xs:attribute name="numProducto" type="ID" use="required" />
<!-- Añadimos el atributo pesoKg -->
<xs:attribute name="pesoKg" type="xs:decimal" />
<!-- Añadimos el atributo enviarPor que es de tipo simple derivado -->
<xs:attribute name="enviarPor">
  <xs:simpleType>
    <xs:restriction base="xs:string">
      <xs:enumeration value="aire" />
      <xs:enumeration value="tierra" />
    </xs:restriction>
  </xs:simpleType>
</xs:attribute>

Comentarios

¿Has encontrado un error? ¿Crees que algo podría mejorarse? No dudes en comentármelo y estaré encantado de echarle un vistazo.