Este tutorial tiene como objetivo presentar la tecnología de una manera sencilla y práctica de forma que se comprenda rápidamente su aplicación y beneficios. En el mismo se presentará la definición de tipos simples y compuestos, cómo declarar atributos, realizar restricciones de ocurrencias sobre los elementos, cómo derivar tipos (herencia) y se nombrarán los tipos predefinidos del lenguaje más comunes.

Diego Sánchez Schenone , Arquitecto de Software, IBM China

Desde el año 2004, Diego Sánchez Schenone se ha desempeñado como consultor, comenzando como programador J2EE Senior, Arquitecto de Software y Líder de Tecnología primariamente para Toyota Argentina S.A. Actualmente en IBM desempeña el rol de WME Specialist en el área de Global Delivery / E-Business Hosting, brindando soluciones de middleware. Ante cualquier consulta o comentario contactar a Diego por email a la dirección schenone@ar.ibm.com..



16-12-2010

Introducción

XML Schema es un lenguaje que permite definir la gramática que determina la estructura que un documento XML (llamado instancia) debe tener. Como se mencionó en el artículo previo, esta validación se puede realizar con un DTD, pero esta última tecnología tiene limitantes para hacer validaciones avanzadas (como por ejemplo verificar que un elemento asuma un valor numérico o sea un dato de tipo fecha).

Este tutorial tiene como objetivo presentar la tecnología de una manera sencilla y práctica de forma que se comprenda rápidamente su aplicación y beneficios. En el mismo se presentará la definición de tipos simples y compuestos, cómo declarar atributos, realizar restricciones de ocurrencias sobre los elementos, cómo derivar tipos (herencia) y se nombraran los tipos predefinidos del lenguaje más comunes.


Elementos: complexType y element

XML Schema es un lenguaje basado en XML, es decir que a la hora de definir un Schema se está definiendo un documento XML en si mismo.

El contenido de un archivo de XML Schema será un conjunto ordenado de elementos, donde cada uno tendrá un propósito y semántica específica, perteneciendo los mismos al espacio de nombres de XML Schema.

Existen muchos elementos dentro del lenguaje para estudiar, pero para poder a comenzar a definir de manera rápida un esquema, se hace necesario conocer en principio a los elementos element y complexType.

El elemento complexType permite definir elementos de estructuras complejas, es decir, elementos que pueden tener elementos hijos y atributos. Para entender esto se analiza la siguiente instancia que representa a una ciudad. Como se observa en el ejemplo, el elemento ciudad es complejo dado que tiene elementos hijos.

                    <?xml version="1.0" encoding="UTF-8"?>
                <ciudad>
                     <codigoPostal>3000</codigoPostal>
                     <nombre>Santa Fe</nombre>
                     <provincia>Santa Fe</provincia>
                </ciudad>

Para la instancia anterior se tendrá el siguiente documento de XML Schema que define su estructura.

 <?xml version="1.0" encoding="UTF-8"?>
 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                targetNamespace="http://www.ibm.com"
                xmlns="http://www.ibm.com" elementFormDefault="qualified">
     
 <xsd:element name="ciudad">			 
     <xsd:complexType>
         <xsd:sequence>
             <xsd:element name="codigoPostal" type="xsd:positiveInteger"/>
             <xsd:element name="nombre" type="xsd:string"/>
             <xsd:element name="provincia" type="xsd:string"/>
          </xsd:sequence>    
         </xsd:complexType>
     </xsd:element>
     
 </xsd:schema>

De este simple ejemplo ya se puede aprender mucho. Como se mencionó, se utiliza complexType para definir la estructura del objeto ciudad, esto se realiza dentro del elemento que se está declarando. Para indicar la secuencia en que aparecen sus hijos se debe utilizar sequence, y dentro de esto último se deben poner los hijos de “ciudad” en el orden que corresponda.

Mediante el uso de element es posible definir tipos simples, es decir, elementos sin estructura y atributos.

        <xsd:element name="codigoPostal" type="xsd:positiveInteger"/>
            <xsd:element name="nombre" type="xsd:string"/>
            <xsd:element name="provincia" type="xsd:string"/>

Element tiene dos atributos mandatorios. El atributo name indica el nombre del elemento que se está declarando, mientras que type se utiliza para decir de qué tipo de datos es.

XML Schema soporta una gran variedad de tipos predefinidos (tipos built-in), los cuales se relacionan casi de manera directa con los tipos de datos de los lenguajes de programación.

La siguiente tabla muestra algunos de los tipos de datos más comunes.

Tipo de datoDescripción
booleanRepresenta los valores de verdad true o false.
stringCadena de caracteres.
integerNúmero entero. A su vez el mismo se especializa en:
  • long.
  • int.
  • short.
  • byte.
dateRepresenta una fecha.
doubleNúmeros con parte entera y decimal.
positiveIntegerNúmeros enteros mayores a cero.

Tipos de datos definidos por el usuario

Una característica avanzada de XML Schema, es que permite definir nuevos tipos de datos. En el ejemplo anterior no se definió ningún tipo de dato, simplemente se indicó la estructura que el elemento ciudad debería tener.

    <xsd:element name="ciudad">			 
    <xsd:complexType>
        <xsd:sequence>
        <xsd:element name="codigoPostal" type="xsd:positiveInteger"/>
                <xsd:element name="nombre" type="xsd:string"/>
                <xsd:element name="provincia" type="xsd:string"/>
        </xsd:sequence>    
    </xsd:complexType>
</xsd:element>

La ventaja de definir un tipo de dato es que luego el mismo se puede utilizar en otras definiciones, al igual que pasa en los lenguajes de programación cuando se define una variable de un tipo dado. El siguiente ejemplo muestra una variación del schema anterior, ahora definiendo un tipo de dato llamado tipoCiudad.

                    <?xml version="1.0" encoding="UTF-8"?>
                    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                    targetNamespace="http://www.ibm.com"
                    xmlns="http://www.ibm.com" 
                    elementFormDefault="qualified">
                
                
                <xsd:element name="ciudad" type="tipoCiudad" />
                
                
                <xsd:complexType name="tipoCiudad">
                    <xsd:sequence>
                    <xsd:element name="codigoPostal" type="xsd:positiveInteger"/>
                    <xsd:element name="nombre" type="xsd:string"/>
                    <xsd:element name="provincia" type="xsd:string"/>
                    </xsd:sequence>    
                </xsd:complexType>
                
                
            </xsd:schema>

Otro ejemplo donde queda claro la ventaja de utilizar tipos de datos es en la siguiente situación. Se quiere modelar un viaje de larga distancia de colectivo. El viaje se compone entre otros de: un código de viaje, una ciudad destino y una ciudad origen.

Como puede observarse en la estructura del viaje, el objeto ciudad aparece más de una vez, por lo que la mejor opción es declarar un tipo que modele la ciudad y luego reutilizarlo tanta veces como sea necesario.

            <?xml version="1.0" encoding="UTF-8"?>
            <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.ibm.com"
            xmlns="http://www.ibm.com" elementFormDefault="qualified">
    
    <xsd:element name="viaje" type="tipoViaje" />
    
    <xsd:complexType name="tipoViaje">
        <xsd:sequence>
        <xsd:element name="codigoViaje" type="xsd:int" />   		
            <xsd:element name="origen" type="tipoCiudad" />
            <xsd:element name="destino" type="tipoCiudad" />
            …
            …
        </xsd:sequence>
    </xsd:complexType>
    
    
    <xsd:complexType name="tipoCiudad">
        <xsd:sequence>
        <xsd:element name="codigoPostal" type="xsd:positiveInteger"/>
                    <xsd:element name="nombre" type="xsd:string"/>
                    <xsd:element name="provincia" type="xsd:string"/>
        </xsd:sequence>    
    </xsd:complexType>
    
</xsd:schema>

Definición de atributos

Cuando un elemento tiene un atributo implica que se debe crear un tipo complejo y la definición del atributo se realiza dentro del elemento complexType.

XML Schema proporciona el elemento <xsd:attribute name=”” type=””/> para definir atributos. El siguiente fragmento modela un tipo de datos persona, donde el DNI es un atributo de la persona.

    <xsd:complexType name="tipoPersona">
       <xsd:sequence>
               <xsd:element name="apellido" type="xsd:string"/>
               <xsd:element name="nombre" type="xsd:string"/>
       </xsd:sequence>    
       
       <xsd:attribute name="dni" type="xsd:positiveInteger" use="required"/>
       
    </xsd:complexType>

Para indicar si el atributo es opcional u obligatorio se debe utilizar use=””, donde los valores que puede asumir son required (obligatorio), optional (opcional) y prohibited (no debe aparecer)


Grupos de atributos

En caso que un elemento tenga más de un atributo se puede definir de manera separada el conjunto de atributos y luego referenciarlo desde el elemento que los necesita. Una de las ventajas de este modo de definición es que facilita la lectura del documento XML Schema y luego se hace más fácil mantenerlo.

El siguiente fragmento muestra la declaración de un grupo de dos atributos que luego es referenciado desde otro tipo.

            <?xml version="1.0" encoding="UTF-8"?>
            <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.ibm.com"
            xmlns="http://www.ibm.com" 
            elementFormDefault="qualified">

<xsd:element name="persona" type="tipoPersona" />

<xsd:complexType name="tipoPersona">
    <xsd:sequence>
    <xsd:element name="apellido" type="xsd:string"/>
            <xsd:element name="nombre" type="xsd:string"/>
    </xsd:sequence>    
    <xsd:attributeGroup ref="atributosPersona"/>
</xsd:complexType>

<xsd:attributeGroup name="atributosPersona">
            <xsd:attribute name="dni" type="xsd:positiveInteger" use="required"/>
            <xsd:attribute name="sexo" type="xsd:string" use="required"/>
</xsd:attributeGroup>

</xsd:schema>

Tipos simples y restricciones

Un tipo simple es aquel que solo permite contener texto en el elemento que se está declarando. Recordar que si el elemento tiene descendientes o atributos, es un tipo complejo.

En los ejemplos desarrollados ya se han declarado tipos simples, esto se realiza con el elemento <xsd:element name=”” type=”” /> en su forma básica .

Además se puede indicar si el elemento toma un valor por defecto o si necesariamente el elemento debe tener un valor particular. El siguiente ejemplo muestra estas situaciones.

                    <xsd:element name=”pais” type=”xsd:string” default=”Argentina” />
                    
                    <xsd:element name=”pais” type=”xsd:string” fixed=”Argentina” />

En el primer ejemplo se indica que si en la instancia el elemento no tiene contenido, asuma por defecto el valor “Argentina”. El segundo caso, obliga a que el elemento tome el valor de “Argentina”, de lo contrario el documento será inválido.

Otra situación que frecuentemente sucede es la de indicar la cantidad de ocurrencias de un elemento. Para esto, XML Schema proporciona los atributos maxOccurs y minOccurs, los cuales se aplican al elemento element.

                    <xsd:element name="antecedenteLaboral" type="xsd:string"
                    minOccurs="2" maxOccurs="10"/>

El ejemplo anterior modela la experiencia laboral de una persona (fragmento de un XML Schema que modela un CV). En tal ejemplo se indica que al menos se debe tener 2 experiencias laborales y como máximo 10. En caso que no se quiere poner un límite, se puede utilizar la siguiente declaración.

                    <xsd:element name="antecedenteLaboral" type="xsd:string"
                    minOccurs="2" maxOccurs="unbounded"/>

Los atributos de ocurrencias se pueden aplicar tanto a tipos simples como tipos compuestos.

Restricciones

A veces es necesario que un tipo simple tenga ciertas características, como por ejemplo que sea una número entero y este en el intervalo [0,100]. Otro ejemplo puede ser, que el valor sea de tipo string, pero que solo asuma alguno de los siguientes valores: ES, EN y BR.

Para solucionar estas situaciones, XML Schema permite definir tipos simple de datos pero con restricciones. A continuación se listan una serie de ejemplos prácticos que muestran estas características avanzada del lenguaje.

                 <xsd:simpleType name="codigoPais" >
                     <xsd:restriction base="xsd:string">
                     <xsd:enumeration value="ES" />
                 <xsd:enumeration value="EN" />
                 <xsd:enumeration value="BR" />
                     </xsd:restriction>    
                 </xsd:simpleType>

El fragmento de código previo define un tipo de datos simple llamado codigoPais. Para indicar que se quiere aplicar una restricción al valor se utiliza el elemento restriction, donde también se indica el tipo al cual se le aplica la restricción usando el atributo base. En el ejemplo se quiere aplicar una restricción al conjunto de valores, por lo que se debe utilizar el elemento enumeration para indicar cada valor.

Otra situación que sucede mucho en la práctica es cuando se necesita restringir el rango de valores de un número entero. El siguiente ejemplo muestra como se resuelve esto.

                    <xsd:simpleType name="tipoEdad" >
                    <xsd:restriction base="xsd:integer">
                            
                            <xsd:minInclusive value="18"/>
                            <xsd:maxInclusive value="30"/>
                            
                        </xsd:restriction>
                    </xsd:simpleType>

Como se observa en el código, en la restricción se indica que el tipo que se restringe es integer. Para indicar el rango de valores se utilizan los elementos minInclusive y maxInclusive. Otros elementos que se pueden aplicar a valores numéricos son minExclusive y maxExclusive.

Otra característica avanza de XML Schema es la de definir expresiones regulares para indicar que un string deba respetar cierto patrón de ocurrencia. Por ejemplo, si se quisiera modelar el tipo de datos patente, se tendría que indicar de alguna manera que una patente tiene 6 caracteres, donde los tres primeros son letras y los tres últimos números. De no respetar ese patrón se estaría ingresando una patente inválida.

                    <xsd:simpleType name="tipoPatente" >
                    <xsd:restriction base="xsd:string">
                    <xsd:pattern value="[A-Z]{3}[0-9]{3}"/>
                        </xsd:restriction>
                    </xsd:simpleType>

En el código previo se modela una patente. La restricción indica que se realiza sobre el tipo string. Para trabajar con expresiones regulares se debe utilizar el elemento pattern y en el atributo value poner la expresión regular.

La expresión [A-Z] indica que se solo pueden ser letras en mayúsculas. Agregando {3} se establece la cantidad de ocurrencias, en este caso 3 letras en mayúsculas. La expresión [0-9]{3} es similar pero se restringe a dígitos.

Del ejemplo puede observarse lo poderoso que es este mecanismo, con solo una siempre expresión regular se puede validar el conjunto de valores que se espera que el elemento tenga.


Extendiendo un tipo de dato

Se puede decir que XML Schema permite la herencia entre tipos de datos, queriendo indicar que un tipo puede heredar las características de un tipo padre y a su vez agregar nuevos atributos.

El ejemplo típico que aparece en los libros de programación orientada a objetos es que se tiene una clase Persona y luego se la especializa en Estudiante y Profesor dado que estos últimos son personas, pero además agregan características propias. Recordar que en la programación orientada a objetos también se heredan los métodos, en XML Schema solo se trata la estructura del tipo.

Previamente este concepto de herencia ya se presentó cuando se restringió el tipo string al momento de definir el tipo codigoPais. Técnicamente lo que se estaba realizando era derivar el tipo con una restricción.

El otro mecanismo es el de derivación por extensión, el cual permite extender el modelo de contenido del tipo que se está derivando con el modelo del nuevo subtipo.

En el siguiente ejemplo se realizará una derivación por extensión. Para ello hay que crear un nuevo tipo complejo (complexType) y utilizar los elementos complexContent (para indicar que tendrá elementos) y extensión (para especificar el tipo a cual se extiende).

Como ejemplo se va a extender el tipo tipoPersona, creando a partir de este un nuevo tipo llamado tipoAlumno.

                    <?xml version="1.0" encoding="UTF-8"?>
                    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                    targetNamespace="http://www.ibm.com"
                    xmlns="http://www.ibm.com" elementFormDefault="qualified">
     
     <xsd:element name="alumno" type="tipoAlumno" />
     
     <xsd:complexType name="tipoPersona">
         <xsd:sequence>
         <xsd:element name="apellido" type="xsd:string"/>
                    <xsd:element name="nombre" type="xsd:string"/>
         </xsd:sequence>    
         <xsd:attributeGroup ref="atributosPersona"/>
     </xsd:complexType>
     
     <xsd:attributeGroup name="atributosPersona">
                    <xsd:attribute name="dni" type="xsd:positiveInteger" use="required"/>
                        <xsd:attribute name="sexo" type="xsd:string" use="required"/>
     </xsd:attributeGroup>			 
     
     <xsd:complexType name="tipoAlumno">
         <xsd:complexContent>
         <xsd:extension base="tipoPersona">
                 <xsd:sequence>
                 <xsd:element name="carrera" type="xsd:string"/>
                        <xsd:element name="materiasAprobadas" type="xsd:integer"/>
                        <xsd:element name="cantidadAplazos" type="xsd:integer"/>
                 </xsd:sequence>
             </xsd:extension>
         </xsd:complexContent>
     </xsd:complexType>
     
     
 </xsd:schema>

El siguiente documento XML muestra una instancia de alumno válida de acuerdo a la gramática definida.

                    <?xml version="1.0" encoding="UTF-8"?>
    <alumno   dni="28938233" sexo="mujer" 
        
        xmlns="http://www.ibm.com" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="http://www.ibm.com Alumno.Schema.xsd">
        
        <apellido>Bella</apellido>
        <nombre>Fabiola</nombre>
        
        <carrera>Ingenieria en Sistemas de Informacion</carrera>
        <materiasAprobadas>10</materiasAprobadas>
        <cantidadAplazos>12</cantidadAplazos>
        
    </alumno>

Resumen

Como puede verse, esta tecnología es de gran utilidad para realizar validaciones avanzadas de estructuras de documentos XML. Por el uso de la misma, se pueden ahorrar grandes tiempos de desarrollo de software dado que no se necesitaría programar las validaciones de contenido para cada instancia de XML.

Con sólo la definición del schema y teniendo las APIs para el procesamiento de XML (ya todas desarrolladas), es fácil realizar las validaciones sobre los documentos sin necesidad de ponerse a reinventar la rueda.

Como todas las tecnologías de avanzada que estos días frecuentemente se utilizan (y lamentablemente poco se conocen o mal usan) es vital realizar un buen diseño de documentos XML y sus correspondientes reglas gramaticales. Es tarea del Arquitecto de Software conocer de estas buenas prácticas y aplicarlas a las necesidades del negocio para brindar soluciones profesionales de valor agregado.

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=SOA y servicios web
ArticleID=603393
ArticleTitle=XML y Tecnologías Relacionadas: XML Schema
publish-date=12162010