XML
Introduction XML: eXtensible Markup Language Défini par le consortium W3C A l’origine, proposé comme langage d’annotation (en remplacement ou en complément à HTML, SGML, …) pas en tant que langage pour BD Les documents contiennent des tags qui décrivent le contenu <Cours> <Titre_cours>XML</Titre_cours> <Section> <Titre>Introduction</Titre> <Texte> XML: eXtensible …</Texte> </Section> … </Cours>
Introduction Contrairement à HTML On peut définir nous même les tags On ne s"intéresse a priori qu’au contenu et non à la forme de la présentation du document La présentation est définie en des endroits différents Le but du W3C était (est ?) de remplacer HTML pour ajouter de la sémantique aux documents du WEB
Introduction Actuellement, XML est plutôt utilisé comme langage d’échange de données entre applications Plusieurs communautés ont défini des standards de représentation de données basés sur XML ChemML, BSML (BioSequenceML), GraphML, … Chaque standard définit des restrictions pour valider les documents en utilisant Des outils de spécification de type Les DTD (Document Type Description) XML schemas Une description textuelle de la sémantique XML autorise l’ajout de nouveaux tags, mais ceux-ci sont contraints par les DTD Plusieurs outils pour valider, interroger et afficher les documents XML
Structure d’un document XML(1) Tag: c’est le label ou l’étiquette d’une partie des données Élément : c’est une partie de données commençant par un <nom_de_tag> et se terminant par </nom_de_tag> Les éléments peuvent être imbriqués Les éléments doivent être correctement imbriqués <personne> <nom> Dupont <prénom> Jean </prénom></nom> </personne> Chaque document doit obligatoirement n’avoir qu’un seul élément au niveau le plus haut
L’imbrication d’éléments(1) L’imbrication est utile lors du transfert de données <commandes> <commande> <num_cde> 112 </num_cde> <client> ABCD </client> <produit> <num_prod> 123_132</num_prod> <prix> 200 </prix> <qté> 40 </qté> </produit> … </commande> </commandes>
L’imbrication d’éléments (2) L’imbrication est prohibée ou découragée dans les bases de données relationnelles La théorie de la normalisation nous incite à ne pas créer la table Cde(NumC, DateC, NumProduit, num_cl, nom_cli, Prix, Quantité) En BD relationnelle, l’imbrication est remplacée par le concept de clé étrangère Cde(NumC, DateC, num_cl), Cli(num_cl, nom_cli), CP(NumC, numP, quantité), Prod(NumProduit, Prix) L’imbrication est appropriée quand il faut transférer les données car les application externes n’ont pas un accès direct aux données référencées par les clés étrangères
Structure d’un document XML (2) Le mixage de texte avec les sous-éléments est autorisé dans XML <lettre> Bonjour <destinataire> M. Dupont </destinataire> … </lettre> Ceci est utile pour les documents du type texte auxquels on veut ajouter des « repères » mais déconseillé lorsqu’il s’agit de transférer des données Tout le contenu doit être décrit !!
Les attributs Les éléments peuvent avoir des attributs <compte type="chèque"> <numC>150</numC> <solde>100</solde> … </compte> Les attributs sont spécifiés par nom_att=valeur dans le tag de début de de l’élément Un élément peut avoir plusieurs attributs <compte type="chèque" numC="150"> <solde>100</solde>
Attributs Vs. Sous-éléments Dans le contexte des documents (texte), les attributs font partie du marquage (description) alors que les sous-éléments constituent le contenu Dans le contexte de l’échange de données, la distinction est loin d’être claire (voir l’exemple précédent) En fait, XML a été historiquement proposé par des spécialistes des langages à marques (markup languages) tels que SGML qui s’intéressent à la structuration des documents (ex: documentation technique) Suggestion : Dans le cadre de la manipulation des données, utiliser les attributs pour l’identification des éléments (voir plus loin)
Un peu plus sur la structure Les éléments sans sous-éléments ou sans texte peuvent être abrégés <compte num="150" type="chèque" solde="100"/>
Document bien formé Un document est bien formé si Il a une seule racine Chaque tag ouvrant a un tag fermant qui lui correspond Chaque attribut n’apparaît qu’une seule fois dans un tag ouvrant, sa valeur doit être spécifiée et entre "
Les espaces de noms : Namspaces Les données XML doivent être échangées entre organisations Le même tag risque d’être utilisé avec différents sens causant des confusions La spécification d’un nom unique pour un élément permet de résoudre le problème Meilleur solution, utiliser Namespace:nom_local Namespace: désigne une URI où les tags sont définis, ou bien un alias à une URL
Espace de nom : (exemple) <société xmlns="http://abcd.com/societes" xmlns:per="http://abcd.com/personnes"> <nom> abcde </nom> <employés> <employé> <per:nom> Jean Dupont</nom> </employé> </employés> </société> Le tag <nom> est utilisé avec deux sens, une première fois pour désigner le nom d’une société et une deuxième fois pour désigner le nom d’une personne. Le Namespace par défaut est http://abcd.com/societes. L’autre a un alias " per "
Définition du schéma Le schéma d’une BD fixe l’organisation logique des données qu’on peut stocker ainsi que leurs types Les documents XML ne sont pas obligés d’avoir un schéma Cependant, quand il s’agit d’échanger des données, il devient nécessaire de fixer la structure pour pouvoir ensuite écrire les applications qui les exploitent Il existe deux mécanismes Les DTD (Document type definition) Très utilisées Les XML schemas Plus récents, plus riches et bien plus compliquées donc moins utilisés
Les DTD Elles spécifient Quels éléments peuvent apparaître dans le document Quels attributs peuvent/doivent apparaître dans le document Quels sous-éléments peuvent/doivent apparaître dans le document Les DTD ne contraignent pas le type de données Tout est chaîne de caractères Syntaxe <!ELEMENT élément (spécification_des-sous-éléments)> <!ATTLIST élément(attributs)>
Spécification des éléments dans une DTD Les sous-éléments peuvent être spécifiés comme Noms d’éléments #PCDATA (chaînes de caractère) EMPTY (pas de sous-éléments) ANY (n’importe quoi) Exemple <!ELEMENT livre(titre, année, auteur+, mot_clé*)> <!ELEMENT titre (#PCDATA)> <!ELEMENT année (#PCDATA)> <!ELEMENT auteur(nom, prénom)> <!ELEMENT nom (#PCDATA)> <!ELEMENT prénom (#PCADATA)> <!ELEMENT mot_clé (#PCDATA)>
Spécification des attributs dans une DTD Pour chaque attribut Son nom Son type CDATA (chaîne) ID (identificateur ~clé) IDREF (fait référence à un ID ~ clé étrangère) IDREFS (ensemble de références) Si Il est obligatoire (#REQUIRED) Il a une valeur par défaut (valeur) Sinon (#IMPLIED) Exemple: <!ATTLIST compte( type CDATA "chèque" Num ID #REQUIRED)> <!ATTLIST client( idCli ID #REQUIRED comptes IDREFS #REQUIRED)>
ID et IDREF Un élément ne peut avoir plus d’un attribut du type ID La valeur de l’attribut de type ID doit être unique pour chaque élément dans le document Dans l’exemple précédent, un compte et un client ne peuvent avoir le même ID !!! Un attribut du type IDREF doit contenir une valeur qui correspond à un ID dans le même document
Critique des DTD Pas de typage Pas possible d’exiger que l’élément <age> doit contenir un entier. Le seul type c’est PCDATA (ou CDATA pour les attributs) Par défaut, les éléments sont triés Exemple: <!ELEMENT a(b,c)> <!ELEMENT b (#PCDATA)> <!ELEMENT c (#PCDATA)> Le document <a><c>123</c><b>456</b></a> n’est pas conforme à la DTD car <c> arrive avant <b> Il aurait fallu faire <!ELEMENT a((c,b)|(b,c))> Avec n attributs, il y a n! ordres possibles
Critique des DTD ID et IDREF ne sont pas typés Exemple : <!ATTLIST compte( type CDATA "chèque" Num ID #REQUIRED)> <!ATTLIST client( idCli ID #REQUIRED comptes IDREFS #REQUIRED)> si l’attribut Comptes fait référence à l’ID d’un client alors cela sera considéré comme correcte !!! Pourvu que l’ID existe dans le document La même contrainte pour IDREFS
XML Schema C’est un outil plus sophistiqué que les DTD. Permet de spécifier Les types Contraintes sur les valeurs min/max De nouveaux types utilisateur XML schema est lui même défini en XML Intégré aux Namespaces (contrairement aux DTD) Permet de définir des clés et des clés étrangères … MAIS: BIEN PLUS COMPLQUE QUE LES DTD
XML Schema: Exemple <xsd:schema xmlns:xsd=http://www.w3.org/2001/XMLSchema> <xsd element Name="banque" type ="banque_type"/> <xsd:element Name="compte"> <xsd:complexType> <xsd:sequence> <xsd:element Name="no_cte" type "xsd:string"/> <xsd:element Name="agence" type "xsd:string"/> <xsd:element Name="solde" type "xsd:decimal"/> </xsd:sequence> </xsd:complexType> </xsd:element> … définition du client … <xsd:complexType Name="banque_type"> <xsd:element ref="compte" minOcuurs="0" maxOccurs="unbounded"/> <xsd:element ref="client" minOcuurs="0" maxOccurs="unbounded"/> </xsd:schema>
Interrogation et transformation Transformation d’un document d’un schéma à un autre Récupérer une information contenue dans un document Les deux tâches sont très liées et sont souvent prises en charge par les mêmes outils XPATH Langage simple avec expressions de chemins XSLT Langage simple pour la transformation XMLXML et XMLHTML XQuery, XQL, Quilt, XML-QL, … Langages de requêtes plus élaborés
Modèle arborescent (1) <?xml version="1.0" encoding="ISO-8859-1"?> <CINEMA No = "125"> <NOM> Epée de Bois </NOM> <Adresse> 100 rue neuve </Adresse> <Bus> Ligne F </Bus> </CINEMA>
Modèle arborescent (2) No 125 CINEMA NOM ADRESSE BUS 100 rue neuve Epée de Bois Ligne F Les nœuds sont des éléments, des attributs ou des chaînes (nœuds terminaux)
Modèle arborescent Les nœuds éléments ont des éléments fils qui peuvent être soit des éléments, soit des attributs soit des chaînes Les fils d’un élément sont triés dans l’ordre de leur apparition dans le document XML Tous les nœuds ont un et un seul parent sauf la racine Les nœuds attributs ont obligatoirement un fils de type chaîne mais pas de petit-fils
XPATH Le principe de XPATH consiste à utiliser des « expressions de chemin » pour sélectionner des parties du document Le même principe que pour les répertoires Le résultat d’une expression de XPATH est un « ensemble » de valeurs ou d’éléments/attributs
XPATH(2) /a/b/c retourne l’ensemble <c> c1 </c> Exemple <a> <b> <c> c1 </c> </b> <c> c2 </c> </a> /a/b/c retourne l’ensemble <c> c1 </c> <c> c2 </c> /a/b retourne <b><c>c1</c></b> <b><c>c2</c></b> /a/b/c/text() retourne c1 c2
XPATH (3) Le symbole ‘/’ initial désigne la racine de l’arbre Les expressions de chemins sont évaluées de gauche à droite On peut poser des conditions sur des valeurs <a> <b><c>c1</c><d>d1</d></b> <b><c>c2</c><d>d2</d></b> </a> /a/b[d="d1"] retourne <b><c>c1</c><d>d1</d></b>
XPATH(4) Les attributs sont accédés par @ /a/b[c="c1"]/@num retourne l’attribut num associé aux éléments b qui ont un fils c dont la valeur associée est "c1" XPATH utilise aussi des fonctions /a/b[c/count() > 2] retourne les éléments b qui ont des fils de type c eux mêmes ayant plus de deux fils XPATH permet aussi de sélection l’élément en se basant sur sa position /document/section[position()=2] retourne la section 2 du document
XPATH(5) Les attributs IDREF et IDREF peuvent être utilisés pour récupérer les éléments auxquels ils font référence /banque/compte[@num="250"]/id(@titulaire) retourne le titulaire du compte dont le numéro est 250 Le symbole // permet de « sauter » plusieurs niveaux /a//d permet de sélectionner les éléments d descendants d’un nœud a. d n’est pas nécessairement un fils de a. Le symbole .. désigne un parent /a//d[../c] retourne les nœuds d descendants de a et dont le parent a un fils c Et plus encore …
XSLT XSLT est un langage basé sur XPATH qui permet de faire des transformations XML XML XML HTML XML WML (pour WAP) On a un fichier .xml et un autre .xsl
XSLT Deux types d’utilisation pour la visualisation par un browser HTML Fich.xml Processeur XSLT Browser Fich.html Fich.xsl Browser Fich.xml Fich.xsl
XSLT La deuxième approche suppose l’utilisation d’un browser qui récupère les deux fichiers et qui fait le traitement localement. Problème: A part IE qui peut le faire (et encore) les autres (Netscape version <4, Opera, … ) ne peuvent pas faire ce traitement (c’était vrai en 2002) Conclusion: Pour être le plus indépendant des browsers, utiliser plutôt la première approche.
Structure de base: les règles Règle= template. Elément de base pour produire le résultat Une règle s’applique dans le contexte d’un nœud de l’arbre L’application d’une règle produit un fragment du résultat Un programme XSLT est un ensemble de règles permettant de construire un résultat Les règles sont de la forme Lorsque « condition » faire « action » La condition permet de sélectionner des nœuds L’action permet de récupérer une partie des données et le cas échéant lui appliquer des modes de présentation à la HTML
Exemple FILM TITRE Réalisateur Année Hitchcock 1958 Vertigo
Un exemple Produire une phrase quand on rencontre un nœud FILM <xsl:template match= "FILM" > J’ai rencontré un nœud FILM </xsl: template> Motif de sélection : match="Film" L’action de la règle: produit la phrase qui représente le contenu de l’élément template.
Extraction de données On insère dans le résultat des fragments du document traité Exemple: recherche du TITRE pour le nœud FILM <xsl: template match= "FILM"> <xsl: value-of select ="TITRE" /> </xsl: template> Plus généralement, on spécifie le chemin d’accès à un nœud à partir du nœud courant en utilisant des expressions de XPATH Condition Action
Illustration FILM Match=‘FILM’ select=‘TITRE’ TITRE Réalisateur Année Hitchcock 1958 Vertigo
Une règle complète <xsl:template match=“FILM”> <html> <head> <title> Film: <xsl:value-of select =“TITRE”/> </title> </head> <body> l’année de sortie du film est <b><xsl:value-of select=“Année”/></b> </body> </html> </xsl:template>
Le résultat Appliquée au fichier précédent, on obtient <html> <head> <title>Film: Vertigo </title> </head> <body> l’année de sortie du film est <b>1958</b> </body> </html>
Production d’un document XML <xsl:template match="/banque/client"> <xsl:element Name="client"> <xsl:value-of select="nom"/> </xsl:element> </xsl:template> Ceci peut retourner <client>Dupont</client>
Création d’attributs Pour ajouter des attributs, il faut utiliser la construction xsl:attribute Ex: <xsl:template match = "/banque"> <client> <xsl:attribute Name="num"> <xsl:value-of select="Client/numero"/> </xsl:attribute> <nom> <xsl:value-of select="Client/nom"/> </nom> </client> </xsl:template>
Autre exemple <a> <b>1</b> <b>2</b> <xsl:template match="a"> <xsl:value-of select ="b"/> </xsl:template> Retourne : 1 En fait, value-of retourne le premier b trouvé. Que faut-il faire pour retourner tous les <b> ? Pour cela il faut utiliser la construction xsl:apply-template <a> <b>1</b> <b>2</b> <b>3</b> </a> <xsl:template match="/a"> <xsl:apply-templates select="b"/> </xsl:template>
template et apply-templates Avec template, l’attribut match prend une valeur XPATH Avec apply-templates, l’attribut select prend une valeur XPATH <?xml version="1.0" encoding="ISO-8859-1"?> <COURS CODE="TC234"> <SUJET>Publication XSLT</SUJET> <ENSEIGNANTS> <!-- Enseignant responsable --> <NOM>Amann</NOM> <NOM>Rigaux</NOM> </ENSEIGNANTS> <PROGRAMME> <SEANCE ID="1">Documents XML</SEANCE> <SEANCE ID="2">Programmation XSLT</SEANCE> <ANNEE>2002</ANNEE> </PROGRAMME> </COURS>
Exemple (suite) On veut récupérer les noms, l’identificateur de la séance et le texte associé à la séance <xsl:template match="/"> <xsl:apply-templates select="//NOM"/> <xsl:apply-templates select="//SEANCE/@ID"/> <xsl:apply-templates select="//SEANCE"/> </xsl:template> L’expression XPATH dans apply-templates sert à désigner (ou sélectionner) un ensemble de nœuds L’expression XPATH dans template exprime une condition sur les nœuds Cette règle peut être lue: pour tout nœud satisfaisant /, exécuter les 3 actions de la règle Cette règle est toujours déclenchée car il y a au moins (exactement) un élément racine
Exemple (suite) "//NOM" retourne tous les nœuds du type nom (il y en a 2). Si on rajoute la règle <xsl:template match="NOM"> <NOM><xsl:value-of select="."/></NOM> </xsl:template> Chacun des nœuds sélectionné avec la première action satisfait le match de la règle, donc son action est exécutée.
Exemple (suite) On fait pareil pour les deux autres actions : On rajoute les règles <xsl:template match="@ID"> <IDSEANCE><xsl:value-of select="."/></IDSEANCE> </xsl:template> <xsl:template match="PROGRAMME/SEANCE"> <SEANCE><xsl:value-of select="."/></SEANCE>
XQuery Inspiré de SQL Aussi puissant que XSLT mais beaucoup plus simple XQuery 1.0 standard fin 2002
structure générale : XQuery : Introduction FOR déclarations des variables WHERE condition RETURN document expression FLWR
Inscrit.xml …/… <Inscrits> <Inscrit> <Etudiant EtuId=“111111111” Nom=“Jon Doe” /> <CrsChoisi CodeCours=“CS308” Semestre =“H1997” Note=“B” /> <CrsChoisi CodeCours =“MAT123” Semestre =“H1997” Note =“B” /> <CrsChoisi CodeCours =“EE101” Semestre =“H1997” Note =“A” /> <CrsChoisi CodeCours=“CS305” Semestre =“H1995” Note =“A” /> </Inscrit> <Etudiant EtuId=“987654321” Nom=“Bart Simpson” /> <CrsChoisi CodeCours =“CS305” Semestre=“H1995” Note =“C” /> <CrsChoisi CodeCours =“CS308” Semestre=“H1994” Note =“B” /> </Inscritt> …/…
Inscrit.xml (suite) <Inscrit> <Etudiant EtuID=“123454321” Nom=“Joe Blow” /> <CrsChoisi CodeCours=“CS315” Semestre=“P1997” Note=“A” /> <CrsChoisi CodeCours=“CS305” Semestre=“P1996” Note=“A” /> <CrsChoisi CodeCours=“MAT123” Semestre=“P1996” Note=“C” /> </Inscrit> <Etudiant EtuID=“023456789” Nom=“Homer Simpson” /> <CrsChoisi CodeCours=“EE101” Semestre=“H1995” Note=“B” /> </Inscrits>
Xquery: Exemple Exemple: Résultat: FOR $t IN document(“Inscrits.xml”)//Inscrit WHERE $t/CrsChoisi/@CodeCours = “MAT123” RETURN $t/Etudiant Résultat: <Etudiant EtuId=“111111111” Nom=“Jon Doe” /> <Etudiant EtuId=“123454321” Nom=“Joe Blow” />
XQuery : Exemple La requête précédente ne produit pas un résultat XML bien formé. <ListeEtudiants> { FOR $t IN document(“Inscrit.xml”)//Inscrit WHERE $t/CrsChoisi/@CodeCours = “MAT123” RETURN $t/Etudiant } </ListeEtudiants> FOR : instancie $t avec les éléments ‘Inscrit’, WHERE : permet de poser une condition et RETURN : permet de placer les étudiants comme des sous-éléments de ‘ListeEtudiants’.
Restructuration de documents Au lieu d’avoir la liste des étudiants avec chacun de ses cours, obtenir la liste des cours avec chacun des étudiants qui s’y sont inscrits: FOR $c IN distinct(document(“Inscrit.xml”)//CrsChoisi) RETURN <Cours CodeCours = {$c/@CodeCours} Semestre = {$c/@Semestre}> { FOR $t IN document(“Inscrit.xml”)/Inscrit WHERE $t/CrsChoisi/@CodeCours = $c/CodeCours RETURN $t/Etudiant SORTBY ($t/Etudiant/@EtudID) } </Cours> SORTBY ($c/@CodeCours)
Restructuration de documents Les éléments retournés par la requête sont de la forme: <Cours CodeCours=“CS305” Semestre=“F1995” > <Etudiant EtudID=“111111111” Nom=“John Doe” /> <Etudiant EtudID=“987654321” Nom=“Bart Simpson” /> </Cours> Problème: L’élément ci-dessus sera retourné deux fois: Une fois quand $c est instanciée par <CrsChoisi CodeCours=“CS305” Semestre=“H1995” Note=“A” /> La deuxième quand $c est instanciée par <CrsChoisi CodeCours=“CS305” Semestre=“H1995” Note=“C” /> On verra plus loin comment résoudre ce problème
Sémantique de XQuery Etape 1: produit une liste d’instatiations de variables La clause FOR associe à chaque variable une liste de noeuds spécifiés par une expression qui peut être: Une expression Xpath Une requête Xquery Une fonction qui retourne une liste de noeuds
Exemple: Sémantique de XQuery Supposons que la clause FOR déclare $A et $B $A est associé aux noeuds {v,w}; $B à {x,y,z} Alors FOR produit la liste des associations suivantes: $A/v, $B/x $A/v, $B/y $A/v, $B/z $A/w, $B/x $A/w, $B/y $A/w, $B/z
Sémantique de XQuery Etape 2: garder les associations en évaluant la clause WHERE Exemple: WHERE $A/CrsChoisi/@CodeCours =$B/Class/@CodeCours Association: $A/w, où w = <CrsChoisi CodeCours=“CS308” …/> $B/x, où x = <Class CodeCours=“CS308” … /> Comme w/CrsChoisi/@CodeCours = x/Class/@CodeCours, alors la clause WHERE est satisfaite les associations sont retenues.
Sémantique de XQuery Etape 3: Construire le résultat Pour chaque tuple d’associations, instancier la clause RETURN Ceci constitue une partie du résultat
Fonctions et XQuery : Exemple Signature de la Fonction Compter le nombre de sous-éléments récursivement: DEFINE FUNCTION countNodes(element $e) RETURNS integer { RETURN IF empty($e/*) THEN 0 ELSE sum(FOR $n IN $e/* RETURN countNodes($n)) + count($e/*) } expression XQuery fonctions prédéfinies sum, count et empty
Restructuration en utilisant les fonctions DEFINE FUNCTION extraire_liste_cours(element $e) RETURNS element* { FOR $c IN $e//CrsChoisi RETURN <Cours CodeCours={$c/@CodeCours} Semestre={$c/@Semestre} /> } <cours_inscrits> FOR $c IN distinct( FOR $d IN document(“Inscrit.xml”) RETURN extraire_liste_cours($d) ) RETURN <Cours CodeCours = {$c/@CodeCours} Semestre = {$c/@Semestre} > { LET $trs := document(“Inscrit.xml”) FOR $t IN $trs//Inscrit[CrsChoisi/@CodeCours=$c/@CodeCours and CrsChoisi/@Semestre=$c/@Semestre] RETURN $t/Etudiant SORTBY ($t/Etudiant/@EtudID) </Cours> </cours_inscrits>
Aggregation: Exemple La liste des étudiants ainsi que le nombre de cours auxquels ils sont inscrits: FOR $t IN document(“Inscrits.xml”)//Inscrit, $s IN $t/Etudiant LET $c := $t/CrsChoisi RETURN <EtudiantRésumé EtudID = {$s/@EtudID} Nom = {$s/@Nom} TotalCours = {count(distinct($c))} /> SORTBY (EtudiantRésumé/@TotalCours)
Quantification et XQuery XQuery permet de l’exprimer: SOME () et EVERY () Exemple: FOR $t IN document(“Inscrit.xml”)//Inscrit WHERE SOME $ct IN $t/CrsChoisi SATISFIES $ct/@CodeCours = “MAT123” RETURN $t/Etudiant Presque équivalent à: FOR $t IN document(“Inscrit.xml”)//Inscrit, $ct IN $t/CrsChoisi WHERE $ct/@CodeCours = “MAT123” En fait, si les étudiants peuvent prendre plusieurs fois le même cours, le résultat peut être différent.