En el post anterior se trataba de ver de forma más o menos exhaustiva los elementos simples y ante todo los tipos que se pueden aplicar o crear y las restricciones que se pueden añadir. Partiendo de esa base ya podemos centrarnos en los elementos complejos y con eso ya podremos crear XSD completos.
 
Hay cuatro tipos de elementos complejos:
- Elementos que contienen otros elementos
- Elementos que solamente contienen texto
- Elementos que pueden tener tanto otros elementos como texto
- Elementos vacíos.
 

Elementos que contienen elementos

 
Era lógico poder tener algo así.
Un ejemplo:
<xs:element name="system">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="version" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element> 
 
En xml podría ser:
<system>
<name>Windows</name>
<version>3.11 para trabajo en grupo</version>
</system>
 
Al escribirlo de esa manera solo podrá existir un elemento system con esos atributos.
Si quisieramos que hubiera otros elementos con LAS MISMAS características lo tendríamos que
definir así, si el xs:element:
 
<xs:complexType name="system">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="version" type="xs:string"/>
    </xs:sequence>
 </xs:complexType>
 
 
Y así sí, podemos crear otros elementos del mismo tipo complejo:
<xs:element name="mobile" type="system" />
<xs:element name="tablet" type="system" />
 
Lo primero que llama la atención en el elemento system es el indicador <xs:sequence>. Eso se explica más adelante en los indicadores
 
Por cierto podemos hacer que un elemento extienda a otro, es decir, que represente
lo mismo pero con elementos añadidos. Ojo a la etiqueta.
 
 
<xs:complexType name="mage">
  <xs:sequence>
    <xs:element name="name" type="xs:string"/>
    <xs:element name="type" type="xs:string"/>
  </xs:sequence>
</xs:complexType>
 
<xs:complexType name="archmage">
  <xs:complexContent>
    <xs:extension base="mage">
      <xs:sequence>
        <xs:element name="level" type="xs:int"/>
        <xs:element name="order" type="xs:string"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>
 
en XML:
 
<archmage>
<name>Skeleton</name>
<type>Necromancer</type>
<level>10</level>
<order>Order of the Leech</order>
</archmage>
 

Elementos que solamente contienen texto

Estos elementos tienen como contenido un simple texto y pueden tener atributos.
Por ejemplo
<personaje id="666">Demonio</personaje>
 
 
Se pueden definir de dos formas, como una extensión o con restricciones. Lo único que hay que indicar es que el texto que contienen tiene que ser de algún tipo. Puede ser de algún tipo básico u otro definido por nosotros. Y luego aparte podemos meter atributos:
 
<xs:element name="personaje">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="tipo_en_el_que_basa">
      <!-- podemos meter atributos aquí -->
<xs:attribute name="xx" type="tipo_atributo">
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>
 
Con restricciones:
 
<xs:element name="personaje">
  <xs:complexType>
    <xs:simpleContent>
      <xs:restriction base="tipo_en_el_que_basa">
        <!-- podemos meter atributos aquí -->
<xs:attribute name="xx" type="tipo_atributo">
      </xs:restriction>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>
 
Por ejemplo:
 
<xs:element name="personaje">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="xs:string">
      <!-- podemos meter atributos aquí -->
<xs:attribute name="id" type="xs:int">
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>
 
<personaje id="666">Demonio</personaje>
 
 
 

Elementos que pueden tener tanto otros elementos como texto

Este sería una mezcla de los dos anteriores, debemos añadir el atributo mixed="true"
 
<xs:element name="paragraph">
  <xs:complexType mixed="true">
    <xs:all>
      <xs:element name="url" type="xs:anyURI"/>
      <xs:element name="number" type="xs:int"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
 
En XML sería:
<paragraph>
Bla bla bla <url>http://pello.io</url> con un total
de <number>666</number> visitas al día bla bla bla..
</paragraph>
 

Elementos vacíos

Sí, puede ser, son elementos que lo único que tienen son atributos. Si haces un poco de memoria en el propio xhtml existen este tipo de elementos, como <img>, <input> ...
 
Por ejemplo:
<xs:element name="person">
  <xs:complexType>
    <xs:attribute name="name" type="xs:string"/>
    <xs:attribute name="age" type="xs:int"/>
  </xs:complexType>
</xs:element>
 
en xml:
<person name="Ignacio" age="-41" />
 
Si queremos que los atributos tengan alguna restricción:
<xs:element name="person">
  <xs:complexType>
      <xs:attribute name="name" type="xs:string"/>
    <xs:complexContent>
      <xs:restriction base="xs:integer">
        <xs:attribute name="age" type="xs:positiveInteger"/>
      </xs:restriction>
    </xs:complexContent>
  </xs:complexType>
</xs:element>
 
Ahora ya no admitiría edades negativas
 

Indicadores

Antes nos llamaba la atención en indicador sequence. 
<xs:element name="sistema">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="nombre" type="xs:string"/>
      <xs:element name="version" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:element> 
 
Existen varios tipos de indicadores:
 
- sequence: dentro irán dos elementos seguidos y que en el documento XML deben ir en el mismo orden!!.
-all: en el XML salen todos los elementos o no, en cualquier orden. 
-choice: no pueden salir todos los elementos internos ¡solo uno de ellos!
 
<xs:element name="tipo">
  <xs:complexType>
    <xs:choice>
      <xs:element name="guerrero" type="guerrero"/>
      <xs:element name="mago" type="mago"/>
    </xs:choice>
  </xs:complexType>
</xs:element>
 
en xml:
<tipo>
<mago>Gandalf</mago>
</tipo>
 
También podemos añadir indicadores de ocurrencia para poder decir cuántes veces puede aparecer un elemento.
 
-maxOccurs/minOccurs: indica el número máximo/mínimo de veces que puede apacer un elemento. Téngase en cuenta
que en indicador de elementos all el maxOccurs solo podrás ser 1 y el minOccurs 0 o 1.
Si queremos que sea infinito pondríamos maxOccurs="unbounded"
 
Por ejemplo, podemos tener un elemento warrior que tiene un nombre y puede llevar entre 1 y 10 armas:
 
<xs:element name="weapon">
<xs:simpleType>
    <xs:restriction base='string'>
    <xs:restriction base="xs:string">
      <xs:whiteSpace value="collapse"/>
    </xs:restriction>
    </xs:restriction>
</xs:simpleType>
</xs:element>
 
<xs:element name="warrior">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="weapon" type="weapon" minOccurs="1" maxOccurs="10" />
    </xs:sequence>
  </xs:complexType>
</xs:element>
 
En XML:
 
<warrior>
<name>Tronak the Barbarian</name>
<weapon>Sword of Steel</weapon>
<weapon>Battle Axe</weapon>
<weapon>Spiked Club</weapon>
<weapon>Hammer of War</weapon>
</warrior>
 
 
El elemento grupo:
 
Con este elemento podemos agrupar elementos o atributos y luego indicar ese grupo dentro de tipos complejos sin necesidad de reescribir todos los elementos. En caso de que más de un elemento complejo comparta un conjunto de elementos, si los agrupamos podemos reutilizarlos. Y lo mismo con los atributos. Si más de un elemento complejo comparte los atributos podemos agruparlos.
 
<xs:group name="characterdata">
  <xs:sequence>
    <xs:element name="name" type="xs:string"/>
    <xs:element name="race" type="xs:string"/>
    <xs:element name="guild" type="xs:string"/>
  </xs:sequence>
</xs:group>
 
Ahora en player en lugar de indicar name, race,... metemos el grupo:
<xs:element name="player">
  <xs:complexType>
    <xs:sequence>
<xs:group ref="characterdata"/>
      <xs:element name="weapon" type="weapon" minOccurs="1" maxOccurs="10" />
    </xs:sequence>
  </xs:complexType>
</xs:element>
 
en el XML:
<player>
<name>Radagast</name>
<race>Human</race>  <!-- I know I know... don't make me go to check Silmarilion again.. -->
<guild>Wizard</guild>  
<weapon>Mocus</weapon>
<weapon>Cannabis Leaf</weapon>
</player>
 
Y con los atributos los mismo:
<xs:attributeGroup name="playerinfo">
  <xs:attribute name="name" type="xs:string"/>
  <xs:attribute name="strength" type="xs:int"/>
  <xs:attribute name="intelligence" type="xs:int"/>
</xs:attributeGroup>
 
<xs:element name="player">
  <xs:complexType>
  <xs:complexType>
    <xs:attributeGroup ref="playerinfo" />
  </xs:complexType>
  </xs:complexType>
</xs:element>