TUTORIELS 
Manipuler des données XML sous Oracle
Plusieurs solutions existent pour stocker des données au format XML dans une base de données relationnelle, et récupérer ces informations ensuite. Découverte de l'outil "Oracle XSU" (XML SQL Utility).  (11 octobre 2001)
 

Les utilitaires "XML-SQL" d'Oracle correspondent à des classes Java offrant deux principales fonctionnalités :
- Extraire des données d'une base au format XML.
- Insérer des données au format XML dans une base.

Cet outil est fourni en standard à partir d'Oracle 8i (version 8.1.7 et plus) ainsi que sous Oracle 9i.

Pour se connecter aux données, "XML-SQL" utilise des connexions JDBC. Bien que cet utilitaire puisse fonctionner avec n'importe quel driver JDBC, ceux fournis par Oracle sont optimisés.

De la base vers le schéma XML

La classe "OracleXMLQuery" permet de construire un document XML à partir d'une requête SQL. Voici un exemple basique de son utilisation : (source Oracle)

import java.sql.*;
import oracle.xml.sql.query.*;
import oracle.jdbc.driver.*;

public class sample
{
     public static void main(String args[]) throws Exception
     {
          DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
          Connection conn =
          DriverManager.getConnection("jdbc:oracle:oci8:scott/tiger@");
          OracleXMLQuery qry = new OracleXMLQuery(conn, "select * from employes");
          System.out.println(qry.getXMLString());
          conn.close();
     }
}

Si nous considérons que la table "employes" a été créee par le script suivant :

CREATE TABLE employes (
EMPNO NUMBER,
ENAME VARCHAR2(20),
JOB VARCHAR2(20),
MGR NUMBER,
HIREDATE DATE,
SAL NUMBER,
DEPTNO NUMBER
);

... alors, suite à la requête "select * from employes", notre fichier XML ressemblera à ceci :

<?xml version='1.0'?>
<ROWSET>
     <ROW num="1">
          <EMPNO>7369</EMPNO>
          <ENAME>Smith</ENAME>
          <JOB>CLERK</JOB>
          <MGR>7902</MGR>
          <HIREDATE>12/17/1980 0:0:0</HIREDATE>
          <SAL>800</SAL>
          <DEPTNO>20</DEPTNO>
     </ROW>

     <!-- rangées supplémentaires... -->

</ROWSET>
(Afin de rendre ce code encore plus clair, vous pouvez le copier/coller dans un fichier.xml et l'ouvrir sous IE5 par exemple).

Notre document XML a donc été conçu grâce à l'exploitation d'un resultset JDBC par la classe "OracleXMLQuery". On note que les noms des balises XML sont issus des noms de colonnes de la requête SQL (des alias peuvent aussi être utilisés). <ROWSET>" constitue le tag "racine" du document XML, il entoure chacun des tags "<ROW...> (comportant un numéro), qui eux-mêmes délimitent chacun des tuples ramenés par la requête.

Si ce cas "d'école" a le mérite d'être simple, il ne correspond pas forcément aux structures de données d'une "vraie" base. Que faire par exemple face à une table construite autour de type définis par l'utilisateur ? Exemple : (source Oracle)

(Une adresse est d'abord créée sous forme d'un objet)
CREATE TYPE AddressType AS OBJECT (
STREET VARCHAR2(20),
CITY VARCHAR2(20),
STATE CHAR(2),
ZIP VARCHAR2(10)
);

Cet objet "AdressType" est ensuite utilisé en tant qu'attribut au sein d'un autre objet "EmployesType" :

CREATE TYPE EmployesType AS OBJECT
(
EMPNO NUMBER,
ENAME VARCHAR2(20),
SALARY NUMBER,
EMPADDR AddressType
);

Pour corser le tout, on retrouve "EmployesType" dans une collection de type :

CREATE TYPE EmployeeListType AS TABLE OF EmployeeType;

Enfin, la table "dept" est créee, elle compte parmi ses attributs un objet et une collection d'objets :

CREATE TABLE dept (
DEPTNO NUMBER,
DEPTNAME VARCHAR2(20),
DEPTADDR AddressType,
EMPLIST EmployeeListType
);

Afin de ne pas surcharger cet article, la version xml obtenue se trouve dans ce document.
Lorsqu'un attribut de type objet (comme "AddressType") existe dans une table, il est "remplacé" lors de la création du document XML par les noms des colonnes utilisés lors de sa création. Ainsi les "sous-éléments" du tag "<DEPTADDR>" vont être "<STREET>", "<CITY>", "<STATE>", et "<ZIP>".
De la même manière, mais avec des niveaux d'imbrication supplémentaires, "EMPLIST", collection d'objets, se transforme en une hiérarchie de tags imbriqués selon la façon dont ils ont été définis.


Du schéma XML vers la base

La classe Oracle prévue à cet effet se nomme "OracleXMLSave". Elle est capable d'insérer, de mettre à jour et de supprimer des données XML. Toutefois, sa seule utilisation ne permet pas de pouvoir insérer dans la base de données des documents XML, parfois complexes. Il faut en effet créer une structure Oracle (objet, vue) correspondant à l'architecture de ces documents.

En fait, si le chemin à parcourir pour aller des données XML vers la base n'est que "l'inverse" de celui qu'on emprunte pour engendrer du XML à partir de la base, il existe tout de même une différence de taille entre les deux : Il n'existe pas de "mapping" entre les attributs XML (les tags) et les champs de la base de données. D'où la necessité de créer une "structure d'accueil" sur mesure pour les documents XML.

Prenons les tags XML suivants :

<DEPT>
     <DEPTNO>100</DEPTNO>
     <DEPTNAME>Sports</DEPTNAME>
     <DEPTADDR>Paris</DEPTADDR>
     <EMPLIST>
          <EMPLIST_ITEM>
               <EMPNO>7369</EMPNO>
               <ENAME>Sebastien</ENAME>
               <SALARY>10000</SALARY>
          </EMPLIST_ITEM>
          <!-- employes supplementaires... -->
     </EMPLIST>
</DEPT>

Il va maintenant s'agir de créer les tables Oracle adaptées pour les "réceptionner". Nous devons également faire correspondre certaines parties de la structure XML à des types que nous allons définir :
- "emp_type" : Les informations liées à l'employé (identifiant, nom, salaire), correspond à <EMPLIST_ITEM>.
- "empc_type" : Décrira une "collection" d'employés, correspond à <EMPLIST>.
- "dept_type" : Définit un département, correspond à <DEPT>.

Au final, des liaisons existent entre chacun de ces types, ils s'imbriquent ici de la manière suivante :

CREATE OR REPLACE TYPE emp_type AS OBJECT (
     empno    NUMBER(4),
     ename    VARCHAR2(50),
     salary      NUMBER(6,2)
);

CREATE TYPE empc_type AS TABLE OF emp_type;

CREATE TYPE dept_type AS OBJECT (
     deptno          NUMBER(3),
     deptname    VARCHAR2(50),
     deptaddr      VARCHAR2(50),
     employes    EMPC_TYPE
);

Les types étant définis, les données XML peuvent être importées et la table (objet) Oracle peut être créee :

CREATE TABLE obj_dept OF dept_type
     NESTED TABLE employes STORE as nested_emp_table;

Si l'on souhaite conserver une structure de tables relationnelles il faut alors passer par une vue :

CREATE VIEW v_dept OF dept_type WITH OBJECT OID(deptno) AS
SELECT d.deptno, d.deptname, d.deptaddr,
     CAST ( MULTISET ( SELECT e.empno, e.ename, e.salary
                                          FROM emp e WHERE e.deptno = d.deptno)
     AS empc_type)
FROM dept d;

Il existe d'autres moyens d'interfacer XML et une base de données. Cela dépend du SGBD utilisé ainsi que de la technologie que l'on souhaite employer. Du Perl en passant par le Java, les bases de données relationnelles multiplient leurs interactions avec XML, de quoi freiner un peu plus la progression des bases natives XML ?

 
[ Arnaud GadalJDNet
 
Accueil | Haut de page