Construyendo el XML Schema
Vale, en los post anteriores hemos visto cómo se crean tanto los tipos simples como los tipos complejos de un documento XML Schema. Por lo que se ve es una herramienta que permite hilar mucho más fino para crear documentos XML mucho más precisos y restrictivos de lo que se podía hacer con el DTD.
Pero ahora bien, ¿cómo se crea un documento completo? ¿Se ponen primero los elementos simples y luego los complejos? ¿Se pone todo del tirón?
Tenemos más de una opción y elegir una u otro puede ir según gustos o percepción de claridad. Yo particularmente recomendaría, en caso de documentos don mucho elemento al menos, iniciar el documento con la declaración de tipos simples, atributos, etc... y luego meter los tipos complejos. En cualquier caso, con IDEs como eclipse podemos crear el fichero XSD de una forma algo más visual para evitar problemas. Si lo hacemos a mano nos indicará errores y tendremos que ir corrigiendo y haciendo botón derecho sobre el fichero XSD y seleccionar Validate. A veces aparece en rojo, ejecutas eso y el error desaparece... eclipse no es perfecto eh amigos del netbeans?
Vamos a ver un ejemplo. Supongamos que tenemos un documento XML que define las características de un personaje de un juego:
<?xml version="1.0" encoding="UTF-8"?>
<character
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="personaje.xsd">
<name>Iker Nieve</name>
<race>Human</race>
<guild>Smith</guild>
<weapons>
<weapon type="axe" damage="5" defence="3" />
<weapon type="shield" damage="2" defence="10" />
</weapons>
<magic>
<spell cost="5">
<name>Hellfire</name>
<type>Elementalist</type>
</spell>
<spell cost="15">
<name>Reanimate</name>
<type>Necromancy</type>
</spell>
</character>
Vamos a ver formas de crear un XSD para este XML:
1. Todo del tirón:
Trabajo de chinos para habernos matao:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="character">
<xs:complexType>
<xs:sequence>
<xs:element name="name">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:whiteSpace value="collapse"/>
<xs:minLength value="8"/>
<xs:maxLength value="15"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="race">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Human"/>
<xs:enumeration value="Orc"/>
<xs:enumeration value="Elf"/>
<xs:enumeration value="Dwarf"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="guild">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Smith"/>
<xs:enumeration value="Cook"/>
<xs:enumeration value="Warrior"/>
<xs:enumeration value="Peasant"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="weapons">
<xs:complexType>
<xs:sequence>
<xs:element name="weapon" minOccurs="1" maxOccurs="10">
<xs:complexType>
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="damage">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="15"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="defence">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="magic">
<xs:complexType>
<xs:sequence>
<xs:element name="spell" minOccurs="0" maxOccurs="10">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Elementalist"/>
<xs:enumeration value="Necromancy"/>
<xs:enumeration value="Cider Remains"/>
<xs:enumeration value="Coffe Remains"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:attribute name="cost">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="15"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
2. La versión separada, mucho más manejable
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Definition of elements -->
<xs:element name="name">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:whiteSpace value="collapse"/>
<xs:minLength value="8"/>
<xs:maxLength value="15"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="race">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Human"/>
<xs:enumeration value="Orc"/>
<xs:enumeration value="Elf"/>
<xs:enumeration value="Dwarf"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="guild">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Smith"/>
<xs:enumeration value="Cook"/>
<xs:enumeration value="Warrior"/>
<xs:enumeration value="Peasant"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="weapon">
<xs:complexType>
<xs:attribute name="type" type="xs:string"/>
<xs:attribute ref="damage" />
<xs:attribute ref="defence" />
</xs:complexType>
</xs:element>
<xs:element name="weapons">
<xs:complexType>
<xs:sequence>
<xs:element ref="weapon" minOccurs="1" maxOccurs="10" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Elementalist"/>
<xs:enumeration value="Necromancy"/>
<xs:enumeration value="Cider Remains"/>
<xs:enumeration value="Coffe Remains"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="spell" >
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element ref="type" />
</xs:sequence>
<xs:attribute ref="cost" />
</xs:complexType>
</xs:element>
<xs:element name="magic">
<xs:complexType>
<xs:sequence>
<xs:element ref="spell" minOccurs="0" maxOccurs="10" />
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- Attributes -->
<xs:attribute name="damage">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="15"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="defence">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="cost">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="15"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<!-- And finally, character -->
<xs:element name="character">
<xs:complexType>
<xs:sequence>
<xs:element ref="name" />
<xs:element ref="race" />
<xs:element ref="guild" />
<xs:element ref="weapons" />
<xs:element ref="magic" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>