Mini-mémoire BDA (T2 2006), Cecile de Mauroy, Thibault Devedeux


XML/SQL: stockage et intégration de données XML

Traduction de requêtes XPath en requêtes SQL pour des documents XML stockés en relationnel


Le langage XML émerge comme standard d’échange de données sur le Web.
Il peut être intéressant de vouloir stocker des données XML dans un SGBD relationnel, et c’est dans ce cadre que s’inscrit cette étude. Après avoir choisi une méthode de stockage de données XML dans un SGBD relationnel, nous nous intéressons ici à la traduction de requêtes XPath en requêtes SQL.


Plan de l’étude :


I. Stockage de données XML dans une BD relationnelle

1) Choix d’une méthode de stockage pour notre problème : un stockage découlant de la relation de parenté.
2) Exemple d’application du stockage sur un fichier XML: menu.xml
3) Menu.xml: représentation arborescente
4) Stockage dans la base de données relationnelle

II. Traduction XPath/SQL au travers d’exemples

1) Exemples de requêtes SQL correspondant à un XPath
2) Recherche d’une méthode systématique de traduction.

III. Implémentation

IV. Conclusion

 


 

I. Stockage de données XML dans une BD relationnelle


1) Choix d’une méthode de stockage pour notre problème : un stockage découlant de la relation de parenté.

Lorsque l’on veut stocker des données XML dans une base de données relationnelle, plusieurs mappings sont possibles, certains privilégiant plutôt la rapidité de la recherche et d’autres un stockage moindre.
Nous avons choisi ici une méthode de stockage centrée sur la relation parent/enfant :
- une table « Parenté » permet de stocker la relation parent/enfant, les balises et la position.
- une table « Feuilles » contient les différentes valeurs attribuées.

Il s’agit d’un format de stockage générique, intéressant pour trouver une méthode de traduction systématique.


2) Exemple d’application du stockage sur un fichier XML: menu.xml

Afin de mieux visualiser le stockage, nous allons nous pencher sur ‘exemple du fichier « menu.xml ».

<menu>

<entree>
<nom>Salade</nom>
<prix>4 euros</prix>
</entree>

<plat_princ>
<nom>Entrecote frites</nom>
<prix>8 euros</prix>
</plat_princ>

<dessert>
<nom>Boule de glace</nom>
<parfums>
<parfum>Vanille</parfum>
<parfum>Chocolat</parfum>
</parfums>
<prix>3,5 euros</prix>
</dessert>

</menu>



3) Menu.xml: représentation arborescente

4) Stockage dans la base de données relationnelle

Nous effectuons le stockage dans les tables « Parenté » et « Feuilles ». On peut ainsi reconstituer le fichier XML de façon exacte.

Parenté
Id
Parent
Label
Type
Position
i1
i0
menu
ref
1
i2
i1
entree
ref
1
i3
i1
plat_princ
ref
2
i4
i1
dessert
ref
3
i5
i2
nom
cdata
1
i6
i2
prix
cdata
2
i7
i3
nom
cdata
1
i8
i3
prix
cdata
2
i9
i4
nom
cdata
1
i10
i4
parfums
ref
2
i11
i4
prix
cdata
3
i12
i10
parfum
cdata
1
i13
i10
parfum
cdata
2

 

Feuilles
Id
Valeur
i5
Salade
i6
4 euros
i7
Entrecote Frites
i8
8 euros
i9
Boule de glace
i11
3,5 euros
i12
Vanille
i13
Chocolat

 


 

II. Traduction XPath/SQL au travers d’exemples

Nous allons maintenant chercher une méthode systématique de traduction de XPath en requêtes SQL. Afin de nous familiariser avec le problème, nous allons tout d’abord étudier quelques exemples avant de trouver un algorithme systématique.


1) Exemples de requêtes SQL correspondant à un XPath


XPATH : /menu/entree/nom

SELECT P3.id
FROM Parente P1, Parente P2, Parente P3
WHERE P3.Label = "nom" and
P2.Label = "entree" and
P2.id = P3.Parent and
P1.Label = "menu" and
P1.id = P2.Parent and
P1.Parent = 0;

Cet exemple permet de trouver une méthode pour traduire les / dans les XPaths.
Le / entre deux balises a et b, indiquant la parenté, se traduit par les « clauses where » suivantes dans la requête SQL :
- une clause établissant le lien de parenté
- les clauses spécifiant le label de la balise (a ou b)

Enfin, si l’un des labels possède une valeur (en fin de parcours), on peut effectuer la jointure entre la table « Feuille » et la table « parenté ».


XPATH : //nom

SELECT P1.id
FROM Parente P1
WHERE P1.Label = "nom";

Cet exemple illustre le // dans le X-Path.
On a alors les clauses where suivantes dans la requête SQL :
- une pour le type de label
- une pour effectuer la jointure avec la table des valeurs.


XPATH : //*[parfum]

SELECT P1.id
FROM Parente P1, Parente P2
WHERE P2.Label = "parfum" and
P2.Parent = P1.id;

Avec //*[parfum], on cherche un nœud ayant pour fils le label ‘parfum’.
On a alors :
- une clause where servant à établir la parenté avec les nœuds fils.
- une clause where servant à préciser le label des nœuds fils (parfum).


XPATH :/menu/dessert[parfums/parfum="Vanille"]/nom

SELECT P5.id
FROM Parente P1, Parente P2, Parente P3, Parente P4, Parente P5, Feuilles F
WHERE P5.Label = "nom" and (1)
P5.Label = P2.id and (2)
P2.Label = "dessert" and (3)
P1.Label = "menu" and (4)
P1.id = P2.Parent and (5)
P4.Label = "parfum" and (6)
P3.Label = "parfums" and (7)
P3.id = P4.Parent and (8)
P3.Parent = P2.id and (9)
P4.id = F.id and (10)
F.Valeur = \"Vanille\" and (11)
P1.Parent = 0; (12)

Ce XPath plus complexe invite à se pencher sur les prédicats [ ].
Il faut trouver les clauses where correspondant au XPath entre les [ ]. Ici il s’agit des clauses 6, 7, 8, 10, 11.
Il faut ensuite effectuer le lien de parenté entre les [ ] et le reste du XPath : clause 9.


XPATH : //parfum[position()=2]

SELECT P1.id
FROM Parente P1
WHERE P1.Label = "parfum" and
P1.position = 2;

Cet exemple fait intervenir une fonction : la fonction position(). Comme la position est indiquée dans la table « Parenté », il est facile d’établir la clause where correspondante.


2) Recherche d’une méthode systématique de traduction.

Avant d’effectuer l’implémentation, établissons le design de la traduction.

Grâce aux exemples, nous avons établi différents cas à étudier :
- a/b
- //a
- //*[X]
- a/b[X]
- a[position()=n]

Pour trouver un algorithme systématique, nous allons établir un tableau permettant de différencier les cas.

Les « mots » XPath seront représentés par des lettres majuscules, et les éléments par des lettres minuscules.

Le tableau ci-dessous n’est pas exhaustif, et permet juste de définir un moyen d’implémentation pour les cas principaux.

 

X-Path

Requête SQL correspondante

X/a

SELECT P1.id
FROM Parenté P1, Parenté P2, autres tables concernées par X
WHERE P1.Label = a and
P2.id = P1.Parent and
clauses concernant X

P2.id correspond au nœud avec lequel il faut établir la parenté dans X

//a

SELECT P1.id
FROM Parenté P1
WHERE P1.Label = "a";

//*[a]

SELECT P1.id
FROM Parenté P1, Parenté P2
WHERE P2.Label = "a" and P2.Parent = P1.id;

//*[X]

SELECT P1.id FROM Parenté P1, ParentéP2, tables concernées par X
WHERE P1.id = P2.Parent and
clauses découlant de X;
(établissement de parenté avec X)

//X

Requête correspondant à X avec SQL, sans qu’il soit nécessaire d’être raccordé à la racine.

X/b[Z]/Y

SELECT P4.id
FROM Parenté P1, Parenté P2, Parenté P3, Parenté P4 Feuilles F1, tables nécessaires pour X, Y,Z
WHERE P2.Label = "b" and
P1.id = P2.Parent and
(P1.id correspond au nœud “fils de X, permet d’établir la parenté”)
P2.id = P3.Parent and (parenté avec Y)
P2.id = P4.Parent and (parenté avec X)
P1.id = F1.id and
Clauses propres à X, Y et Z

//a[position()=n]

SELECT P1.id
FROM Parenté P1
WHERE P1.Label = "a" and P1.position = n;

 


 

III. Implémentation

(Voir le code de l’implémentation en annexe)
Notre implémentation se décompose en 2 parties principales :
- l’analyse de la requête XPath entrante
- la traduction suivant le cas dans lequel on se trouve


Analyse de la requête

Avant de traiter la requête, il convient d’analyser ses caractéristiques.
Une requête XPath de base est du type /X[Y]Z, avec possibilité de définir des axes, d’utiliser des fonctions…
Ainsi, on détecte la présence
- d’un prédicat (soit celle de [ et ])
- de l’axe // en début de requête
- de *
- d’autres éléments suite au prédicat
- d’un test de valeur dans le prédicat (on peut ne vouloir que les éléments qui ont un nœud N, comme on peut vouloir ceux qui ont une feuille F="texte")
- de la fonction position() dans le prédicat

On s’est limité à la fonction position(), et à l’utilisation de * dans les requêtes du type /(ou //)elem1/elem2/…/elemn/*

En effet, l'étoile * sélectionne tous les éléments localisés par ce qui la précède dans le chemin.
Par exemple
- /A/B/C/* sélectionne tous les éléments inclus dans les éléments /A/B/C/
- /*/*/*/E sélectionne tous les éléments E qui ont trois ancêtres. Il est assez difficile dans l’implémentation actuelle, de détecter les 3 *, et de définir les clauses amenant au résultat désirée.

Suite à l’analyse, on obtient plusieurs booléens, qui définissent la requête.
De même, les éléments avant, dans, et à la suite du prédicat sont stockés dans un tableau (en utilisant la fonction PHP explode, par rapport à, entre autres, la chaine "/").

Traduction

On utilise les booléens pour définir :
- les tables qui seront utilisées dans la clause FROM
- les conditions de la clause WHERE permettant de réaliser les jointures
L’implémentation s’est avérée difficile en ce qui concerne la conservation de la syntaxe de la requête SQL (ne pas avoir deux « and » qui se suivent, par exemple), et l’expression de toutes les informations contenues dans la requête XPath.

Il aurait été peut être plus « propre » de différencier les cas, en utilisant des expressions régulières prédéfinies, et en essayant de les faire correspondre à la requête entrante, mais l’utilisation des Regex n’est pas triviale…

Ci-dessous, une capture d’écran du traitement d’une requête :

Site : http://www.tgl0be.org/projets/bda/

 




IV. Conclusion


Nous avons ainsi mis en place une méthode de traduction XPath/SQL. Ceci peut permettre de consulter des données XML stockées sous forme d’un SGBD relationnel.
Néanmoins, les requêtes contiennent beaucoup de jointures sur des tables qui peuvent être de grande taille, et l’on pourrait chercher à optimiser le problème. Le mapping choisi ici permet une faible capacité de stockage mais augmente par contre la taille des tables et donc la rapidité de la recherche.
Nous nous sommes limités ici à une méthode de stockage précise, mais il existe plusieurs mappings possibles. L’optimisation du problème peut varier d’un mapping à l’autre, certains favorisant la recherche dans les tables et d’autres le stockage. Les méthodes de traduction XPath/SQL sont différentes selon le stockage de la base de données, pouvant inviter à une étude de la traduction selon la méthode de stockage utilisée.