LMSGI

Llenguatges de marques i sistemes de gestió d'informació - DAW, DAM, ASIX

View on GitHub

Validació XML amb XSD

Què és l’XSD?

L’XSD (XML Schema Definition Language) és una manera més completa de crear validadors per l’XML.

L’objectiu dels XSD és acabar substituint completament als DTD degut a les limitacions que tenen aquests darrers.

Avantatges:

Actualment es troba en la versió 1.1 (des del 2012) i se’n poden trobar les definicions a la pàgina http://www.w3c.org/XML/Schema

Validació

La majoria dels validadors poden validar els XML Schemas.

Per exemple amb xmllint ho podem fer:

$ xmllint --noout --schema ./exercici.xsd exercici.xml
exercici.xml validates

També es pot fer amb XML Copy Editor, Sublime, Notepad++, VS Code amb l’extensió d’XML, etc.

Associar l’esquema a un fitxer XML

Per fer servir un Schema en el nostre document XML n’hem de definir el lloc on és.

L’especifiquem en l’element arrel del document.

<?xml version="1.0" encoding="UTF-8" ?>
<lliga xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="fitxer.xsd">
    <equip>FC Barcelona</equip>
    <equip>Real Madrid</equip>
</lliga>

El lloc on està el fitxer també pot ser una URL:

xsi:SchemaLocation="http://www.lloc.com/fitxer.xsd"

En l’associació hi definim:

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:NamespaceSchemaLocation="fitxer.xsd"

Poden ser:

Per exemple, si tenim un document XML:

  <?xml version="1.0" encoding="UTF-8" ?>
  <classe>
     <curs>1r ASIX</curs>
     <professor>
         <nom>Pere Pi</nom>
     </professor>
  </classe>

Li definirem on és el fitxer d’esquema en l’etiqueta arrel:

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

Definir un fitxer XML d’esquema

La definició d’un fitxer d’esquema com que està en XML ha de començar amb l’etiqueta d’XML.

L’etiqueta <schema> és l’element arrel dels XML Schema:

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

Com que és XML la etiqueta s’ha de tancar!

Comentaris

Com que es tracta d’un document XML hi podem posar comentaris del tipus:

<!-- Comentari -->

Però també podem fer servir una forma normalitzada de posar-hi informació:

<xs:annotation>
    <xs:documentation>
        Aquest esquema XML està pensat per fer proves. Però aquí hi podria posar qualsevol cosa.
    </xs:documentation>
</xs:annotation>

XML Schemas

En XSD tenim diferents tipus d’etiquetes possibles:

Sempre tindrem com a mínim un tipus complexe (l’arrel del document).

Tipus simples

En Schema un element definit com a simple només conté text.

image

Utilitzant els tipus de dades podem controlar quin és el contingut de les etiquetes.

Exemple per:

XSD

<xs:element name="nom" type="xs:string" />
<xs:element name="any" type="xs:integer"/>

XML

<nom>Xavier</nom>
<any>2020</any>

Tipus de dades

Els tipus de dades principals són:

Tipus Explicació
xs:string Contindrà una cadena de caràcters
xs:decimal Contindrà un número
xs:boolean Contindrà ‘true’ o ‘false’ o (1 o 0)
xs:date Contindrà una data (AAAA-MM-DD)
xs:anyURI Contindrà una referència a un lloc (URL, disc…)

Variants de tipus de dades

Els tipus de dades generalment tenen diverses variants per adaptar-se millor a les dades que han de representar:

Tipus Variants
Text string, normalizedString, token, Name, NMTOKEN, …
Números integer, positiveInteger, negativeInteger, nonNegativeInteger, nonPositiveInteger, long, unsignedLong, int, unsignedInt, byte, unsignedByte, decimal, float, double
Dates duration, dateTime, date, time, gYear, gMonth, gYearMonth, gDay, gMonthDay

Exemples

XSD XML
<xs:element name="dia" type="xs:date" /> <dia>2020-09-15</dia>
<xs:element name="mes" type="xs:gMonth" /> <mes>--3</mes>
<xs:element name="altura" type="xs:integer" /> <altura>220</altura>
<xs:element name="nom" type="xs:string" /> <nom>Pere</nom>
<xs:element name="lloc" type="xs:anyURI" /> <lloc>http://www.iescendrassos.net</lloc>

Altres atributs

Els elements simples també poden tenir altres atributs que ens permetran definir-hi aspectes com:

Valors fixes

Podem definir que un element té un valor fixe definint-lo amb l’etiqueta ‘fixed’

<xs:element name="cap" type="xs:string" fixed="Manel" />

Això ens permet definir:

<cap>Manel</cap>

Però no:

<cap></cap>
<cap>Pere</cap>

Valors predefinits

Podem definir que un element té un valor predefinit definint-lo amb l’etiqueta ‘default’

<xs:element name="cap" type="xs:string" default="Manel" />

Això ens permet definir:

<cap>Manel</cap>
<cap></cap>
<cap>Xavier</cap>

Ocurrències

També es pot definir el nombre de vegades que ha de sortir l’element el document XML.

Podem definir el nombre mínim de vegades que ha d’aparèixer:

<xs:element name="cap" type="xs:string" minOccurs="1" />

També es pot definir el màxim:

<xs:element name="cap" type="xs:string" maxOccurs="3" />

‘unbounded’ implica un número indeterminat de vegades.

 <xs:element name="cap" maxOccurs="unbounded">

Restriccions

Podem definir restriccions als tipus simples perquè s’adaptin a allò que ens interessa.

Definim el tipus amb xs:simpleType i el restringim amb xs:restriction

<xs:element name="naixement">
    <xs:simpleType>
        <xs:restriction base="xs:integer">
            <xs:maxInclusive value="2010" />
            <xs:minInclusive value="1850" />
        </xs:restriction>
    </xs:simpleType>
</xs:element>
Definir tipus

Si hi ha alguna restricció que farem servir més vegades podem definir un tipus amb nom.

<xs:simpleType name="possible_naixement">
        <xs:restriction base="xs:integer">
            <xs:maxInclusive value="2010" />
            <xs:minInclusive value="1850" />
        </xs:restriction>
</xs:simpleType>

Que podrem usar en la definició de l’element:

<xs:element name="vida" type="possible_naixement" />
Tipus de restriccions

Hi ha molts atributs per definir restriccions:

image

Patrons

Els patrons són un avenç força important amb respecte als DTD.

Els patrons els podem definir amb:

image

Per exemple podem fer que el contingut d’un camp tingui forma d’un DNI:

<xs:element name="dni">
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <xs:pattern value="[0-9]{8}[A-Z]" />
        </xs:restriction>
    </xs:simpleType>
</xs:element>

que validaria correctament:

<home>
    <dni>77980433K</dni>
</home>

Llistes

Si volem que el contingut sigui una llista de valors ho podem definir amb xs:list

<xs:element name="partits">
    <xs:simpleType>
        <xs:list itemType="xs:dateTime" />
    </xs:simpleType>
</xs:element>

De manera que podrem definir coses com:

<partits>
    2019-09-12T17:30
    2019-09-19T19:00
</partits>

Unions

També podem fer que el valor de l’element sigui el resultat d’un tipus o d’un altre.

<xs:element name="valor">
    <xs:simpleType>
        <xs:union memberTypes="euros dolars" />
    </xs:simpleType>
</xs:element>

El valor haurà de ser un valor dels tipus “euros” o de “dolars”

S’han de posar tipus obligatòriament

Tipus complexes

Un tipus complexe és un element XML que conté elements fills, atributs o una combinació d’ambdós.

Sempre hi haurà com a mínim un tipus complexe en els documents: l’arrel del document.

Hi ha 4 grans grups de tipus complexes:

  1. element buit: Pot contenir atributs (els tipus simples han de contenir text i aquest no en té)
    • Per exemple: <producte id="123"/>
  2. només text: Conté text i atributs
    • Per exemple: <food type="dessert">Ice cream</food>
  3. només elements: Conté altres elements
  4. contingut mixt: Pot tenir text, atributs i elements.

Els tipus complexes es desglossen en altres tipus complexes o en tipus simples.

Definició de tipus complexes

No hi ha tipus complexes predefinits: els hem de definir nosaltres:

image

ComplexType

El complexType és la base del contingut complexe i el podrem modificar fent servir diferents modificadors:

Tipus complexes amb només elements

Seqüències de fills (sequence)

Seqüències d’elements <xs:sequence> en un ordre determinat.

<xs:complexType nom="persona">
    <xs:sequence>
        <xs:element name="nom" type="xs:string"/>
        <xs:element name="cognom" type="xs:string" maxOccurs="2"/>
    </xs:sequence>
</xs:complexType>

Fills en qualsevol ordre (all)

Quan ens interessi que els elements apareguin en qualsevol ordre fem servir <xs:all>

<xs:complexType nom="persona">
    <xs:all>
        <xs:element name="nom" type="xs:string"/>
        <xs:element name="cognom" type="xs:string"/>
    </xs:all>
</xs:complexType>

image

Una solució alternativa pot ser crear un tipus complexe amb la repetició

image

Seleccions (choice)

Podem definir o bé uns elements o bé uns altres <xs:choice>

<xs:complexType nom="persona">
    <xs:choice>
        <xs:element name="nomCognom" type="xs:string"/>
        <xs:element name="dni"  type="xs:string"/>
    </xs:choice>
</xs:complexType>

Determinisme

S’ha de tenir en compte que davant de cada decisió el processador ha de saber per quin camí ha de tirar.

No es poden fer coses com:

<xs:choice>
    <xs:sequence>
        <xs:element name="nom"/>
        <xs:element name="alies"/>
        <xs:element name="cognom"/>
    </xs:sequence>
    <xs:sequence>
        <xs:element name="nom"/>
        <xs:element name="cognom"/>
    </xs:sequence>
</xs:choice>

Tipus complexes buits

image

Si no té atributs també podria haver definit la etiqueta amb el tipus simple.

Definint-ne la llargada a zero.

<xs:element name="delegat">
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <xs:length value="0"/>
        </xs:restriction>
    </xs:simpleType>
</xs:element>

Tipus complexes mixtes

Un element que pot contenir etiquetes i text es defineix amb mixed="true".

<xs:element name="carta">
    <xs:complexType mixed="true">
        <xs:sequence>
            <xs:element name="nom" type="xs:string" />
            <xs:element name="cita" type="xs:integer" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

XML

<carta>Estimat senyor <nom>Pere<nom>:
Li envio aquesta carta per recordar-li que hem quedat per
trobar-nos el dia <cita>12</cita>
Joan
</carta>

Referències a elements

Podem definir els elements de forma global i després usar-los en les definicions de tipus

<xs:element name="nom" type="xs:string" />
<xs:element name="cognom" type="xs:string" />
<xs:element name="persona">
    <xs:complexType>
        <xs:element ref="nom" />
        <xs:element ref="cognom" />
    </xs:complexType>
</xs:element>

Això ens permetrà reutilitzar-los quan ens facin falta.

Grups d’elements

Si un grup d’elements surten varies vegades podem definir un grup.

<xs:group name="moneder">
        ...
</xs:group>
<xs:group ref="moneder" />

S’han de definir al principi del fitxer.

Atributs

Els atributs són elements simples que sempre estan dins de tipus complexes.

<xs:attribute name="Id" type="xs:string" />

S’hi pot treballar igual que amb els elements:

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

Atributs: use

<xs:attribute name="src" type="xs:anyURI" use="required" />
<xs:attribute name="numero" type="xs:integer" default="1" />
<xs:attribute name="especial" type="xs:integer" fixed="Disabled" />
<xs:attributeGroup name="Persones">
...
</xs:attributeGroup>
<xs:attributeGroup ref="Persones" />
<factura numero="24" empresa="Porquets, SA" />
<element name="factura">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="nom" maxOccurs="1" />
        </xs:sequence>
        <xs:attribute name="numero" type="xs:integer" use="required"/>
        <xs:attribute name="empresa" type="xs:string" />
    </xs:complexType>
</element>

Comparació DTD i XSD

XML

<?xml version="1.0" encoding="iso-8859-1" ?>
<paper>
    <article>
        <head>Títol</head>
        <lead>Introducció</lead>
        <paragraph>Paràgraf de text</paragraph>
    </article>
</paper>

DTD

<!ELEMENT paper (article+)>
<!ELEMENT article (head,lead,paragraph+)>
<!ELEMENT head (#PCDATA)>
<!ELEMENT lead (#PCDATA)>
<!ELEMENT paragraph (#PCDATA)>

XSD

<?xml version="1.0" encoding="iso-8859-1"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="paper">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="article" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="head" type="xsd:string"/>
              <xsd:element name="lead" type="xsd:string"/>
              <xsd:element name="paragraph" type="xsd:string" maxOccurs="10"/>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>