Notes de cours XML

XML

XML (eXtensible Markup Language) est un standard du W3C. Il s'agit d'un format de documents permettant de représenter des données sous forme de texte, tout en conservant une certaine organisation. Le modèle de données sous-jacent est un arbre (voir la section 1.1). Il existe cependant des extensions à XML permettant de considérer des graphes.

Lorsque l'on considère XML, c'est souvent en conjonction avec un ensemble de technologies qui vont permettre de l'utiliser. Voici une partie de ces technologies:

  • Descriptions de la forme des documents, par exemple:
  • Désignation / sélection de parties de documents: XPath, voir aussi la section 2.
  • Liens inter et intra documents:
    • XLink est un standard permettant de créer des liens entre documents XML.
    • XPointer permet au contraire de créer des liens à internes à un document.
  • Transformation et interrogation de documents XML:
    • XSLT est un langage de transformation de documents XML.
    • XQuery est un langage d'interrogation de documents XML. Il est abordé dans la section 3.
  • APIs standard pour lire des documents XML:
    • DOM permet de lire un document XML et de le manipuler sous sa forme d'arbre.
    • SAX permet de parcourir un document XML en utilisant un système basé sur un ensemble d'événements.

Modèle de données XML

Un document XML correspond à un ensemble de données organisées dans un arbre. Cet arbre possède différents types de noeuds:

  • La racine C'est le document dans son entier. Elle possède en particulier un enfant spécifique correspondant au contenu du document. Ses autres enfants correspondent à des déclarations concernant ce document. Par exemple, il peut s'agir de commandes indiquant une feuille de style XSLT.
  • Élément C'est un noeud possédant un nom. Ce nom peut être un nom simple, qui commence par une lettre et se continue par une série de lettres, de chiffres, de ' - ', ' _ ', etc (voir la spécification de XML). Il peut aussi avoir un préfixe, appelé namespace. Il possède le plus souvent un ensemble de fils qui peuvent être de n'importe quel type (sauf la racine). Les fils qui sont des attributs sont considérés séparément des autres fils et sont non ordonnés. De plus il y a au maximum un attribut ayant un nom donné par élément. Les autres fils sont ordonnés et considérés au même niveau, qu'il s'agisse de texte, d'éléments, ou autre.
  • Attribut C'est un noeud qui associe un nom à une valeur. On ne peut trouver ces noeuds que comme enfants d'éléments.
  • Texte Du texte simple.
  • Commentaire Les commentaires sont considérés comme des noeuds à part entière dans l'arbre XML.
  • Commande Ou processing instructions. Ce sont des instructions destinées à l'application qui va traiter le document. Il peut par exemple s'agir d'une feuille de style à utiliser lorsque le document est à présenter sous forme d'une page web.

Exemple

noeuds texte en rouge
attributs en vert
éléments en bleu


Syntaxe de XML

La syntaxe de XML est basée sur des balises tout comme HTML, ou encore SGML qui est leur ancêtre commun.

Déclarations préliminaires

Un fichier XML débute par une série de déclarations optionnelles qui sont suivies d'un élément qui correspond au contenu du document. Parmi les déclarations possibles, deux sont fréquentes:

Le prologue

Il prend la forme d'une commande et permet de fournir un ensemble d'informations sur le document.

<?xml info1="val1" info2="val2" ... ?>

Parmi ces informations, on trouve la version de XML utilisée (version) et qui est presque toujours 1.0, l'encodage des caractères (encoding) ou encore le fait que le document fasse ou non référence à d'autres documents (standalone).


Exemple Le prologue suivant:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

signifie qu'il s'agit d'un document XML version 1.0, que l'encodage des caractères suit la norme unicode sur 8bits (UTF-8) et que le document fait référence à d'autres documents.


Une déclaration de type

Elle est de forme suivante:

<!DOCTYPE le-type [
déclarations supplémentaires ] >

le-type est au choix:

  • nom
  • nom SYSTEM “URL
  • nom PUBLIC identifiant

nom indique le nom de l'élément principal du document, URL indique l'url où peut être trouvée la DTD du document et identifiant indique un identifiant publique pour le type, tel que "-//W3C//DTD XHTML 1.0 Transitional//EN" pour le xhtml en version 1.0 transitionnelle.

Les déclarations supplémentaires correspondent soit à la DTD complète, soit à des déclarations qui s'ajoutent à la DTD.


Exemple La déclaration suivante:

<!DOCTYPE collection SYSTEM "collection.dtd"
[
 <!ENTITY Arl "Arleston">
]>

indique que l'élément principal est nommé collection, que la description du document est donnée dans le fichier collection.dtd et que l'entité Arl correspond au texte Arleston.


Syntaxe des noeuds de l'arbre XML

Attributs

Un attribut s'écrit

nom="valeur"

ou bien

nom='valeur'

Il doit obligatoirement être placé à l'intérieur de la balise ouvrante de l'élément qui est son père.

Éléments

La syntaxe d'un élément est la suivante:

<nom attributs>... enfants qui ne sont pas des attributs ...</nom>

Les attributs d'un élément sont séparés par des espaces. nom est le nom de l'élément.

Un élément sans enfants autres que des attributs peut s'écrire:

<nom attributs/>
Texte

Les noeuds texte sont écrits tels quels, sauf en ce qui concerne les caractères spéciaux:

Caractère Comment l'écrire
< &lt;
> &gt;
" &quote;
' &apos;
& &amp;

Il est également possible d'avoir recours aux sections <tt>CDATA</tt> dont le contenu sera directement interprété comme du texte brut, sans qu'il y ait besoin d'échapper les caractères spéciaux. Leur syntaxe est la suivante:

<![CDATA[contenu brut, sans
échappement]]>
Commentaires

Les commentaires s'écrivent:

<!-- le commentaire 
-->
Les commandes (ou //processing instructions//)

Elles s'écrivent:

<?commande arg1="val1" arg2="val2" ... ?>

Exemple Document XML correspondant à l'exemple d'arbre XML précédent.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE collection SYSTEM "collection.dtd">
<collection>
  <serie nom="Lanfeust de Troy">
    <tome numero="1">
      <scenariste>Arleston</scenariste>
      <dessinateur>Tarquin</dessinateur>
      <titre>L&apos;ivoire du Magohamoth</titre>
    </tome>
    <tome numero="2">
      <dessinateur>Tarquin</dessinateur>
      <titre><![CDATA[Thanos l'incongru]]></titre>
    </tome>
    <editeur nom="Soleil"/>
  </serie>
  <serie nom="Calvin &amp; Hobbes">
    <tome numero="1">
      <titre>Adieu, monde cruel</titre>
    </tome>
  </serie>
</collection>

DTDs

DTD signifie Document Type Definition. Une DTD est une spécification de la structure du document XML. Elle spécifie, pour chaque élément du document, quels peuvent être ses enfants et dans quel ordre ils peuvent apparaître. La DTD d'un document peut être spécifiée soit dans le document lui-même, à l'intérieur des crochets [ ] de la déclaration <!DOCTYPE ...>, soit de manière externe grâce aux définitions SYSTEM ou PUBLIC de <!DOCTYPE ... > (voir la section 1.2.1). Une DTD peut également contenir des définitions d'entités, qui permettent de définir un alias pour un morceau de document XML.

Déclarations <!ELEMENT
Ces déclarations permettent de spécifier le contenu d'un élément, c'est-à-dire quels éléments peuvent apparaître comme enfants de cet élément. Elle permet également de spécifier si l'élément peut contenir du texte. Il est important de noter que ces déclarations ne concernent pas les attributs.

La syntaxe de ces déclarations est <!ELEMENT nom contenu>. contenu peut être au choix:
  • EMPTY: signifie que l'élément ne peut avoir d'enfants.
  • ANY: signifie que l'élément peut avoir n'importe quels enfants.
  • ( #PCDATA | nom1 | nom2 ... )* signifie que l'élément peut avoir comme enfants une alternance de texte et d'éléments nom1, nom2, etc, sans restriction sur le nombre ou l'ordre de ces éléments. On appelle un tel contenu mixed content. C'est par exemple le type de contenu utilisé pour de nombreux éléments en XHTML, tels que div ou p.

  • Une expression régulière de la forme:
    • nom: un élément nom
    • #PCDATA: du texte
    • r1 , r2: concaténation
    • r1 | r2: choix
    • (r1)+: au moins une fois
    • (r1)*: zéro, une ou plusieurs fois
    • (r1)?: zéro ou une fois
    dans lesquelles r1 et r2 sont des expressions régulières et nom est le nom d'un élément.
Exemple 5

<!ELEMENT collection (serie)*>


signifie que l'élément collection ne peut avoir comme enfants que des éléments serie en nombre quelconque.

<!ELEMENT tome (scenariste?,dessinateur?,titre)>


signifie que l'élément tome a comme enfants éventuellement un élément scenariste, ensuite éventuellement un élément dessinateur et enfin exactement un élément titre.


Déclarations <!ATTLIST >


Ces déclarations permettent de spécifier les attributs qui peuvent apparaître dans un élément.

La syntaxe de ces déclaration est:

<!ATTLIST nom declarations d'attributs>


nom est le nom de l'élément considéré et déclarations d'attributs est une suite de déclarations de la forme:
  • nom_att type "valeur": si l'attribut nom_att apparaît, sa valeur doit être du type type. Si l'attribut nom_att n'apparaît pas, il est intégré automatiquement dans l'arbre avec la valeur valeur (i.e. valeur est sa valeur par défaut). Si cette valeur par défaut est précédée de la mention #FIXED, alors c'est la seule valeur autorisée pour cet attribut.
  • nom_att type #REQUIRED: l'attribut nom_att doit apparaître et sa valeur doit être de type type.
  • nom_att type #IMPLIED: l'attribut nom_att est optionnel. S'il apparaît, sa valeur doit être de type type.

Parmi les types existants, on peut avoir les types suivants:
  • CDATA: du texte
  • (val1|val2|...): val1, val2, etc sont les seules valeurs autorisées pour cet attribut.
  • ID: un identifiant pour cet élément. Il y a au maximum un attribut avec un tel type par élément.
  • IDREF (ou bien IDREFS): un identifiant (ou dans le second cas une suite d'identifiants) servant de référence vers un autre élément.
Exemple 6

<!ATTLIST editeur nom CDATA #REQUIRED adresse CDATA #IMPLIED>



signifie que dans un élément editeur, on a obligatoirement un attribut nom qui a comme valeur du texte et éventuellement un attribut adresse qui a également comme valeur du texte.


Déclarations <!ENTITY >


Ces déclarations sont utilisées pour définir des entités, c'est-à-dire un nom pour un morceau de XML. Ce morceau peut être soit directement donné dans la déclaration, soit être le contenu d'un fichier. Cette dernière version permet ainsi d'inclure des fichiers dans le document.

La syntaxe de la déclaration est l'une des trois suivantes:
  • <!ENTITY nom "valeur">: Lorsque l'entité &nom; sera rencontrée dans le document, elle sera remplacée par valeur. Il est important de noter que valeur sera interprété comme du XML et non comme du texte pur. En particulier les balises qui peuvent apparaître dans valeur correspondront bien à des éléments.
  • <!ENTITY nom SYSTEM "url">: Lorsque l'entité &nom; sera rencontrée dans le document, elle sera remplacée par le contenu du document indiqué par url.
  • <!ENTITY nom PUBLIC "identifiant_public" "url">: Lorsque l'entité &nom; sera rencontrée dans le document, elle sera remplacée par le contenu du document indiqué par l'identifiant_public. Le document peut être récupéré en utilisant url, mais également par n'importe quel autre moyen qui correspondrait à identifiant_public, comme par exemple l'utilisation d'une copie locale du fichier.
Exemple 7

<!ENTITY Arl "Arleston">

signifie que l'entité &Arl; sera remplacée par le texte "Arleston".


<!ENTITY Tar "<dessinateur>Tarquin</dessinateur>">



signifie que l'entité &Tar; sera remplacée par un élément dessinateur ayant un enfant qui est un noeud texte ayant comme valeur "Tarquin".
Exemple 8 Document XML avec DTD correspondant à l'exemple 1 d'arbre XML mais cette fois ci avec une DTD définie dans le document lui-même. On peut noter que les entités &Arl; et &Tar; qui sont définies dans cette DTD sont utilisées dans le document.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE collection 
[
<!ELEMENT collection (serie*)>
<!ELEMENT serie (tome+,editeur?)>
<!ATTLIST serie nom CDATA #REQUIRED>
<!ELEMENT tome (scenariste?,dessinateur?,titre)>
<!ATTLIST tome numero CDATA #REQUIRED>
<!ELEMENT scenariste (#PCDATA)>
<!ELEMENT dessinateur (#PCDATA)>
<!ELEMENT titre (#PCDATA)>
<!ELEMENT editeur EMPTY>
<!ATTLIST editeur nom CDATA #REQUIRED adresse CDATA #IMPLIED>
<!ENTITY Arl "Arleston">
<!ENTITY Tar "<dessinateur>Tarquin</dessinateur>">
]
>
<collection>
  <serie nom="Lanfeust de Troy">
    <tome numero="1">
      <scenariste>&Arl;</scenariste>
      &Tar;
      <titre>L&apos;ivoire du Magohamoth</titre>
    </tome>
    <tome numero="2">
      &Tar;
      <titre><![CDATA[Thanos l'incongru]]></titre>
    </tome>
    <editeur nom="Soleil"/>
  </serie>
  <serie nom="Calvin &amp; Hobbes">
    <tome numero="1">
      <titre>Adieu, monde cruel</titre>
    </tome>
  </serie>
</collection>



Un document XML est dit valide si son contenu respecte les déclarations de la DTD. Ainsi le document défini dans l'exemple 8 est valide.

Espaces de nommage (Namespaces)

En programmation, il arrive fréquemment que deux fonctions de deux bibliothèques différentes portent le même nom. De nombreux langages mettent à disposition du programmeur des mécanismes permettant de lever l'ambiguïté qui en résulte. On peut par exemple citer le système de modules de Python ou encore le système de paquets en Java.

Ce problème de nommage peut également survenir en XML, en particulier lorsque l'on cherche à manipuler plusieurs documents simultanément. Par exemple, supposons que l'on accède simultanément à un magasin de vente de livres d'occasion et à une encyclopédie sur la littérature. Supposons que l'on aie un élément annee pour les livres vendus qui correspond à l'année d'impression du livre et un élément annee dans l'encyclopédie qui correspond à l'année de première parution d'un livre. La signification de ces deux éléments est différente et on aimerait pouvoir les distinguer.

Les espaces de nommage (en anglais namespaces) correspondent à des regroupement d'élément. Ils se présentent sous la forme d'URIs, en général des URLs. Le nom complet d'un élément est composé de son espace de nommage et de son nom local.

Exemple 9 Dans le cadre du magasin en ligne on peut prendre comme espace de nommage l'URL du site internet du dit magasin
ex: http://www.livres-pas-chers.com

De même on peut utiliser l'URL du site de l'encyclopédie
ex: http://toutsurleslivres.org


Il se peut également qu'un nom ne soit dans aucun espace de nommage auquel cas sont nom complet se résume à son nom local. C'est le cas des documents que nous avons vu jusqu'ici.

Déclarations des espaces de nommage

Les espaces de nommage peuvent s'utiliser de deux manières: soit en spécifiant un nom logique pour un espace de nommage, soit en spécifiant un espace de nommage par défaut.

La spécification d'un espace de nommage par défaut se fait en utilisant l'attribut spécial xmlns. La valeur de cet attribut est prise comme espace de nommage par défaut pour l'élément de l'attribut, ainsi que pour tous ses éléments descendants (mais pas pour les attributs).

Exemple 10 Dans le document

<livres xmlns="http://www.livres-pas-chers.com">
  <livre>
    <auteur>Stephen King</auteur>
    <titre>Le fléau</titre>
    <annee>2003</annee> <!-- ici c'est l'année d'édition !!! -->
    <prix>5.3</prix>
  </livre>
</livres>

tous les noms d'éléments sont dans l'espace de nommage “http://www.livres-pas-chers.com”.


L'autre manière d'utiliser les espaces de nommage consiste à leur associer un (ou même plusieurs) nom logique, également appelé préfixe d'espace de nommage (namespace prefix). Ils se déclarent en utilisant un attribut de la forme xmlns:prefix, où prefix est le préfixe que l'on souhaite associer à l'espace de nommage. Comme pour le cas précédent, la valeur de cet attribut spécifie l'espace de nommage concerné. On peut ensuite spécifier au coup par coup un espace de nommage pour un élément ou un attribut en utilisant la notation prefix:nomprefix est un préfixe d'espace de nommage et où nom est le nom local de l'élément. Cette notation est appelée nom qualifié (qualified name). La portée de la déclaration est l'élément, ainsi que ses descendants.

Exemple 11 On reprend le document précédent et on l'enrichit quelque peu:

<livres xmlns="http://www.livres-pas-chers.com">
  <livre xmlns:encyclo="http://toutsurleslivres.org">
    <auteur>Stephen King</auteur>
    <titre>Le fléau</titre>
    <annee>2003</annee> <!-- ici c'est l'année d'édition -->
    <encyclo:annee>1978</encyclo:annee> 
      <!-- ici c'est l'année de première parution -->
    <prix>5.3</prix>
  </livre>
</livres>

tous les noms d'éléments sont dans l'espace de nommage “http://www.livres-pas-chers.com”, sauf le deuxième élément annee, qui, lui, est dans l'espace de nommage “http://toutsurleslivres.org”.


Afin de connaître l'espace de nommage associé à un nom, on peut procéder comme suit:
  • Si ce nom est un nom qualifié (i.e. de la forme prefix:nom), alors l'espace de nommage correspond à celui de prefix, et est donné par xxx dans la déclaration de la forme xmlns:prefix="xxx". En cas d'ambiguïté, on prend la déclaration la plus proche de l'élément considéré en remontant dans l'arbre XML.
  • Si ce nom est un nom local (sans préfixe), alors l'espace de nommage est l'espace de nommage par défaut, c'est à dire celui donné par xxx dans la déclaration xmlns="xxx" la plus proche en remontant dans l'arbre XML et en commençant par le noeud courant. Si aucune déclaration de ce type n'apparaît en remontant dans l'arbre XML, alors le nom n'est associé à aucun espace de nommage.