domingo, 25 de enero de 2015

XML Schemas y Xpath (Parte II)

Los atributos en los Schemas deben definirse al final del elemento en el que se aplican, y en la raíz del propio elemento, siguiendo la siguiente estructura:
           
(Modificado en los ejemplos)
               <xs:element name="marca" maxOccurs="unbounded">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="nombres">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="nombre" maxOccurs="unbounded"></xs:element>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                        <xs:attribute name="idcode"></xs:attribute>
                    </xs:complexType>
                </xs:element>

Por defecto, la aparición de los atributos no es obligatoria. Este comportamiento puede modificarse mediante:

            <xs:attribute name="idcode" use=”required”></xs:attribute>

Además, los atributos pueden limitar el tipo de contenido. Por ejemplo, el siguiente obligará a que sean valores numéricos:

            <xs:attribute name="idcode" type=”xs:integer”></xs:attribute>

En el siguiente caso, se podrá limitar a una serie de elementos:

                          <xs:attribute name="estado">
                            <xs:simpleType>
                              <xs:restriction base="xs:string">
                                   <xs:enumeration value="precintado"/>
                                   <xs:enumeration value="nuevo"/>
                                   <xs:enumeration value="usado"/>
                              </xs:restriction>
                            </xs:simpleType>
                          </xs:attribute>

En este otro, se limitan los valores numéricos entre 2 rangos 18 y 30 (ambos inclusive):

                          <xs:attribute name="edad">
                            <xs:simpleType>
                              <xs:restriction base="xs:integer">
                                   <xs:minInclusive value="18"/>
                                   <xs:maxInclusive value="30"/>
                              </xs:restriction>
                            </xs:simpleType>
                          </xs:attribute>

O limitarlo en base a un patrón:

       <xs:attribute name="dias">
            <xs:simpleType>
                <xs:restriction base="xs:integer">
                    <xs:pattern value="\d{4}\D{3}"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:attribute>

Relaciones de dependencia

Los XML Schemas no solo nos permiten establecer limitaciones sobre los elementos, su contenido, posición o número. También nos permite establecer limitaciones en relación a otros elementos del documento. Estas son las llamadas relaciones de dependencia, y muestran una gran similitud a las bases de datos relacionales.

Por ejemplo, partimos de la siguiente dependencia 1:N:


Donde Envío posee 3 campos:
     scod: Código de proveedor.
     pcod: Código de pieza.
     cantidad: Número de unidades de pieza.

En proveedor poseemos:
     codigo: Código de proveedor.
     nombre: Nombre del proveedor.
     ciudad: Nombre de la ciudad.
     status: Estado del proveedor.

En pieza tenemos:
     codigo: Código de la pieza.
     nombre: Nombre del producto.
     Ciudad: Dónde se fabricó.
     Peso: En gramos, el peso del producto.

El documento XML sería:
<?xml version="1.0" encoding="UTF-8"?>
<negocio xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="BaseDatos1.xsd">
    <proveedor>
        <codigo>S1</codigo>
        <nombre>Juanlu</nombre>
        <ciudad>granada</ciudad>
        <status>100</status>
    </proveedor>
    <proveedor>
        <codigo>S2</codigo>
        <nombre>Daniel</nombre>
        <ciudad>Fuengirola</ciudad>
        <status>90</status>
    </proveedor>
    <pieza>
        <codigo>P1</codigo>
        <nombre>tornillo</nombre>
        <ciudad>malaga</ciudad>
        <peso>30</peso>
    </pieza>
    <pieza>
        <codigo>P2</codigo>
        <nombre>tuerca</nombre>
        <ciudad>malaga</ciudad>
        <peso>10</peso>
    </pieza>
    <envio scod="S1" pcod="P1" cantidad="200"/>
    <envio scod="S2" pcod="P2" cantidad="100"/>
    <envio scod="S2" pcod="P1" cantidad="100"/>
</negocio>

En esta relación, tendremos 3 claves primarias:
     En proveedor, clave primaria en codigo.
     En pieza, clave primaria en codigo.
     En envio, clave primaria en scod y pcod.

Las claves primarias se definen mediante la siguiente estructura:

      <xs:key name="{nombre conjunto clave primaria}">
            <xs:selector xpath="{elemento}"/>
            <xs:field xpath="{elemento campo}"/>
        </xs:key>

Por ejemplo:

      <xs:key name="pkProveedor">
            <xs:selector xpath="proveedor"/>
            <xs:field xpath="codigo"/>
        </xs:key>

El pkProveedor será empleado más adelante para, en la clave foránea, unir este conjunto de claves primarias con el otro conjunto de claves. El selector permite seleccionar mediante xpath el elemento del cual se partirá en los xs:field para tomar campos para la clave primaria. El (o los) xs:field, son los campos que formarán parte de la clave primaria.

Lo siguiente sería una clave foránea en la que se relaciona el atributo scod de envio con el conjunto de claves primarias antes definido. La forma de definirlo es:

       <xs:keyref refer="{conjunto claves primarias}" name="{nombre clave foránea}">
            <xs:selector xpath="{elemento que referencia}"/>
            <xs:field xpath="{campo que referencia}"/>
        </xs:keyref>

En el ejemplo:

       <xs:keyref refer="pkProveedor" name="fkProveedor">
            <xs:selector xpath="envio"/>
            <xs:field xpath="@scod"/>
        </xs:keyref>

Así pues, tendríamos como conjunto de claves primarias referenciado pkProveedor, como nombre de esta relación de clave foránea fkProveedor (es obligatorio ponerle nombre a la relación de clave foránea, aunque no se vaya a usar), y el xs:selector y xs:field funcionarán igual que en el xs:key.

El ejemplo completo sería:


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:element name="negocio" type="tipoNegocio">
        <xs:key name="pkProveedor">
            <xs:selector xpath="proveedor"/>
            <xs:field xpath="codigo"/>
        </xs:key>
        <xs:key name="pkPieza">
            <xs:selector xpath="pieza"/>
            <xs:field xpath="codigo"/>
        </xs:key>
        <xs:key name="pkEnvio">
            <xs:selector xpath="envio"/>
            <xs:field xpath="@scod"/>
            <xs:field xpath="@pcod"/>
        </xs:key>ya
        <xs:keyref refer="pkProveedor" name="fkProveedor">
            <xs:selector xpath="envio"/>
            <xs:field xpath="@scod"/>
        </xs:keyref>
        <xs:keyref refer="pkPieza" name="fkPieza">
            <xs:selector xpath="envio"/>
            <xs:field xpath="@pcod"/>
        </xs:keyref>
    </xs:element>
    <xs:simpleType name="codValido">
        <xs:restriction base="xs:string">
            <xs:pattern value="[Ss]\d{1,2}"/> <!-- "[Ss][0-9]{1,2}" -->
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="cValido">
        <xs:restriction base="xs:string">
            <xs:pattern value="[Pp]\d{1,2}"/> <!-- "[Pp][0-9]{1,2}" -->
        </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="v100">
        <xs:restriction base="xs:integer">
            <xs:minInclusive value="0"/>
            <xs:maxInclusive value="150"/>
        </xs:restriction>
    </xs:simpleType>
    <xs:complexType name="tipoNegocio">
        <xs:choice maxOccurs="unbounded">
            <xs:element name="proveedor" type="tipoProveedor"/>
            <xs:element name="pieza" type="tipoPieza"/>
            <xs:element name="envio" type="tipoEnvio"/>
        </xs:choice>
    </xs:complexType>
    <xs:complexType name="tipoProveedor">
        <xs:sequence>
            <xs:element name="codigo" type="codValido"/>
            <xs:element name="nombre" type="xs:string"/>
            <xs:element name="ciudad" type="xs:string"/>
            <xs:element name="status" type="v100"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="tipoPieza">
        <xs:sequence>
            <xs:element name="codigo" type="cValido"/>
            <xs:element name="nombre" type="xs:string"/>
            <xs:element name="ciudad" type="xs:string"/>
            <xs:element name="peso" type="v100"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="tipoEnvio">
        <xs:attribute name="scod" type="xs:string"/>
        <xs:attribute name="pcod" type="xs:string"/>
        <xs:attribute name="cantidad" type="xs:integer"/>
    </xs:complexType>
</xs:schema>

No hay comentarios:

Publicar un comentario

¡Danos tu opinión!