1. Introduction▲
XGQL est un langage procédural utilisant le formalisme XML permettant d'agréger de nombreuses sources de données :
- Plusieurs bases de données (depuis la version 2.0)
- Flux XML, SOAP, Texte
- Session, request et cookie en mode web (depuis la version 2.0)
Via les protocoles suivants :
- File system (Local ou points de montage)
- HTTP
- FTP
- TCP
- JDBC
Nous allons voir comment utiliser ce formalisme.
2. Au commencement fut le namespace▲
Un script XGQL est déclaré dans le namespace <xgql:myTag/>. C'est pour cela qu'un listing XGQL devra débuter de la façon suivante :
<
xgql
:
root
xmlns
:
xgql
=
"http://www.symeria.com/xgql/"
>
</
xgql
:
root>
3. Les variables▲
Une variable XGQL se déclare de la façon suivante :
<
xgql
:
var
name
=
"maVariable"
>
Ma variable</
xgql
:
var>
Par défaut, une variable n'a pas de type, elle peut être de type :
- Entier
- Chaîne de caractères
- XML
Contrairement au XSLT, il est possible de modifier le contenu d'une variable :
<
xgql
:
var
name
=
"maVariable"
>
$maVariable et mon nouveau contenu</
xgql
:
var>
Si vous déclarez une variable dès le début du traitement, celle-ci sera globale. Par contre, si vous la déclarez dans une condition, une fonction ou une boucle, elle sera locale.
3-1. Opérateurs arithmétiques▲
Pour travailler sur les variables, XGQL permet d'utiliser les opérateurs mathématiques de base.
Opérateur | Description |
---|---|
+ | Addition |
- | Soustraction |
* | Multiplication |
/ | Division |
Mod | Modulo |
3-2. Affectation de variable▲
L'affectation de variable s'effectue de la même façon que la déclaration de celle-ci :
<
xgql
:
var
name
=
"maVariable"
>
1</
xgql
:
var>
A ce moment, maVariable vaut 1.
Il est possible d'utiliser tous types d'opérateurs mathématiques :
<
xgql
:
var
name
=
"maVariable"
><
xgql
:
process>
$maVariable + 1</
xgql
:
process></
xgql
:
var>
<!--maVariable est à 2 -->
<
xgql
:
var
name
=
"maVariable"
><
xgql
:
process>
$maVariable * $maVariable </
xgql
:
process></
xgql
:
var>
<!--maVariable est à 4 -->
<
xgql
:
var
name
=
"maVariable"
><
xgql
:
process>
$maVariable mod $maVariable </
xgql
:
process></
xgql
:
var>
<!--maVariable est à 0 -->
L'instruction xgql:process indique qu'il s'agit d'une opération. Sinon, il s'agirait d'une concaténation de chaînes.
xgql:process : permet aussi de réaliser des opérations XQuery, comme par exemple :
<
xgql
:
var
name
=
' maVariable'
>
<
xgql
:
process>
let $doc:=document{<account
id
=
'42'
><name>
Aurel</name><firstnm>
Marc</firstnm><log>
martin_p</log><pwd>
mypassword</pwd></account>
}
return $doc/account/data(@id)
</
xgql
:
process>
</
xgql
:
var>
Ici, maVariable sera à 42, puisqu'il s'agit de la valeur de l'attribut id de l'élément account.
3-3. Opérateurs de chaînes▲
Le but premier du script XGQL étant de générer du XML, il est évidemment possible de travailler sur les chaînes.
<
xgql
:
var
name
=
"maVariable"
>
Ma variable</
xgql
:
var>
maVariable vaut 'Ma variable'.
<
xgql
:
var
name
=
"maVariable"
>
$maVariable et mon nouveau contenu</
xgql
:
var>
maVariable vaut 'Ma variable et mon nouveau contenu'. Bien entendu, les possibilités de traitement de chaînes sont bien plus poussées, puisqu'il est également possible d'accéder à l'ensemble des fonctionnalités XQuery pour le traitement des chaînes. Exemple de concaténation de chaîne en XQuery :
< !-- Renvoi montestmontest -->
<
xgql
:
var
name
=
"maVariable"
><
xgql
:
process>
let $doc := string('montest') return concat($doc, $doc)</
xgql
:
process></
xgql
:
var>
Mais nous ne nous étendrons pas plus sur les fonctions XQuery car ces dernières sont déjà décrites dans d'autres tutoriaux.
3-4. Variables externes▲
xgql:param est la commande qui permet à un script XGQL d'être initialisé par des paramètres extérieurs quand il est utilisé en mode API ou generator cocoon.
Exemple de paramètre :
<
xgql
:
param
name
=
"externalParam"
/>
Cette déclaration est à placer au début du script.
4. Les instructions de contrôle▲
Les instructions de contrôle constituent le squelette du script XGQL. Ce sont ces instructions qui procurent à XGQL sa capacité décisionnelle permettant de contrôler les flux d'exécution du programme.
Les instructions capables de modifier l'exécution du script en fonction des données métiers sont les suivantes :
- xgql:if : exécute un bloc de code lorsque certaines conditions sont satisfaites.
- xgql:while : exécute plusieurs fois un même bloc de code.
4-1. Les tests conditionnels▲
4-1-1. Instruction xgql:if ▲
L'une des fonctionnalités les plus importante est l'instruction xgql:if.
L'instruction xgql:if exécute les instructions si la condition renvoie la valeur booléenne true.
Exemple de délcaration d'un bloc conditionnel :
<
xgql
:
if
test
=
"1 = 1"
>
instruction
</
xgql
:
if>
Ces instructions peuvent être imbriquées :
<
xgql
:
var
name
=
"condition1"
>
true</
xgql
:
var>
<
xgql
:
var
name
=
"condition2"
>
2</
xgql
:
var>
<
xgql
:
if
test
=
"'$condition1' = 'true'"
>
<
xgql
:
if
test
=
"'$condition2' = '2'"
>
instruction
</
xgql
:
if>
</
xgql
:
if>
4-1-2. La branche conditionnel▲
Pour simplifier l'écriture des scripts, il est possible d'exécuter un bloc d'instructions spécifiques si le résultat de la condition est à la valeur booléenne false.
Avec le script suivant :
<
xgql
:
root
xmlns
:
xgql
=
"http://www.symeria.com/xgql/"
>
<
xgql
:
var
name
=
"condition1"
>
true</
xgql
:
var>
<
xgql
:
var
name
=
"condition2"
>
2</
xgql
:
var>
<result>
<
xgql
:
if
test
=
"'$condition1' = 'true'"
>
<
xgql
:
if
test
=
"'$condition2' = '3'"
>
<test1/>
<
xgql
:
else>
<test2/>
</
xgql
:
else>
<test3/>
</
xgql
:
if>
<
xgql
:
else>
<test4/>
</
xgql
:
else>
<test5/>
</
xgql
:
if>
</result>
</
xgql
:
root>
on obtient le résultat suivant :
<result>
<test2></test2>
<test5></test5>
</result>
Dans le deuxième saut conditionnel, il est possible de mettre des instructions après le xgql:else, par contre, il n'est pas possible de mettre plusieurs branches conditionnelles dans le même xgql:if.
Un exemple qui ne fonctionnera pas :
<
xgql
:
root
xmlns
:
xgql
=
"http://www.symeria.com/xgql/"
>
<
xgql
:
var
name
=
"condition1"
>
true</
xgql
:
var>
<
xgql
:
var
name
=
"condition2"
>
2</
xgql
:
var>
<result>
<
xgql
:
if
test
=
"'$condition1' = 'true'"
>
<
xgql
:
if
test
=
"'$condition2' = '3'"
>
<test1/>
<
xgql
:
else>
<test2/>
</
xgql
:
else>
<test3/>
<
xgql
:
else>
<test2/>
</
xgql
:
else>
</
xgql
:
if>
<
xgql
:
else>
<test4/>
</
xgql
:
else>
<test5/>
</
xgql
:
if>
</result>
</
xgql
:
root>
4-1-3. Opérateurs de comparaisons▲
Les opérateurs de comparaisons servent à comparer deux valeurs (variable et constante). Ils renvoient toujours un booléen.
Opérateur | Description |
---|---|
= ou eq | Egal à |
!= | Différent de |
lt ou < | Inférieur à |
gt ou > | Supérieur à |
<= | Inférieur ou égal à |
>= | Supérieur ou égal à |
4-1-4. Opérateurs logiques▲
Les opérateurs logiques peuvent être combinés entre eux pour obtenir des résultats booléens plus fins.
Opérateur | Description |
---|---|
and | Et logique |
or | Ou logique |
not() | Négation |
4-2. Les boucles▲
La boucle xgql:while est une expression proche du xgql:if. Il évalue une expression booléenne et exécute un bloc de code aussi longtemps que l'expression booléenne renvoie true. Il n'existe pas de branchement conditionnel sur le xgql:while.
<
xgql
:
var
name
=
"condition1"
>
0</
xgql
:
var>
<
xgql
:
while
test
=
'$condition1 lt 5'
>
$condition1
<
xgql
:
var
name
=
"condition1"
><
xgql
:
process>
$condition1 + 1</
xgql
:
process></
xgql
:
var>
</
xgql
:
while>
Cet exemple renvoie le résultat suivant : 1234
5. Les procédures▲
Une procédure est un bloc de script qui peut être invoqué à tout moment. Une procédure accepte un ou plusieurs paramètres, mais ne peut pas renvoyer de valeur.
Une procédure se caractérise par trois éléments :
- la balise xgql:function
- un nom de fonction (identifié par l'attribut name)
- un bloc d'instruction
Une procédure peut intéragir avec les variables déclarées en global dans le programme.
<
xgql
:
var
name
=
"var1"
>
5</
xgql
:
var>
<
xgql
:
function
name
=
"func"
>
<
xgql
:
var
name
=
"var1"
>
$var1 - 1</
xgql
:
var>
</
xgql
:
function>
L'appel d'une procédure se fait de la façon suivante :
<
xgql
:
call
name
=
"func"
/>
Attention, si plusieurs procédures ont le même nom, c'est la dernière procédure avant l'appel qui sera interprété.
6. Les sources de données▲
Un des principaux avantages d'XGQL, en plus d'accéder à toutes les fonctionnalités XQuery, est de pouvoir gérer simultanément plusieurs sources de données :
- FTP
- http
- FILE
Les données sont accessibles avec l'instruction xgql:datasource.
<
xgql
:
datasource>
ftp://username:password@ftp.whatever.com/file.zip;type=i </
xgql
:
datasource>
<
xgql
:
datasource>
http://www.symeria.com </
xgql
:
datasource>
<
xgql
:
datasource>
C:/My Documents/ALetter.html</
xgql
:
datasource>
Lors d'une utilisation simple, le flux du datasource sera transcrit directement en résultat du script. Pour travailler sur ce flux, il suffit juste d'encapsuler le xgql:datasource dans une déclaration de variable.
6-1. Travailler sur les données récupérées▲
Bien entendu, il est possible de travailler sur ces datasources en les récupérant dans une variable. Considérons le fichier test.xml dans le répertoire suivant C:\myTest :
<?xml version="1.0" encoding="UTF-8"?>
<account
id
=
'42'
>
<name>
Aurel</name>
<firstname>
Marc</firstname>
<login>
martin_p</login>
<pwd>
mypassword</pwd>
</account>
Pour récupérer son contenu dans une variable XGQL, il suffit de faire la déclaration suivante :
<
xgql
:
var
name
=
"maVariable"
><
xgql
:
datasource>
C:\myTest\test.xml</
xgql
:
datasource></
xgql
:
var>
Il est alors possible de travailler sur cette variable, donc sur le XML qu'elle représente :
<
xgql
:
process>
let $doc:= document{$maVariable} return $doc/account/data(@id)</
xgql
:
process>
Dans cette exemple, xgql:process va renvoyer 42 comme résultat. Ceci illustre la facilité avec laquelle il est possible d'utiliser des sources externes de données afin de la manipuler avec XGQL !
7. Interroger des bases relationnelles▲
Depuis la version 2.0 de XGQL, en plus de gérer de nombreuses sources de données, il est également possible de travailler sur plusieurs bases de données relationnelles simultanément (jusqu'à 6).
7-1. Configuration▲
Le fichier xgql.properties est le fichier de configuration XGQL. C'est dans ce fichier que sont spécifiés les données de connections aux bases de données :
- idConnect : nom de la connexion. Ce nom sera utilisé tout au long du script XGQL pour indiqué quel pool de connexion est utilisé
- className : nom du driver JDBC à utiliser pour se connecter
- url : url d'accès à la base
- login : identifiant de la base
- password : mot de passe pour accéder à la base
Ces informations sont à configurer autant de fois qu'il y a de bases de données à interroger. Exemple de fichier xgql.properties.
# La première connexion est celle par défaut
xgql.connectId=myHsql
xgql.className=org.hsqldb.jdbcDriver
xgql.url=jdbc:hsqldb:file:testdb
xgql.login=SA
xgql.password=
# Les connexion suivantes peuvent actuellement aller de 1 à 5
xgql.1.connectId=mySql
xgql.1.className=com.mysql.jdbc.Driver
xgql.1.url=jdbc:mysql://localhost:3308/valkyrie
xgql.1.login=root
xgql.1.password=pwd
Ici, la configuration est prévue pour interroger deux bases.
7-2. CREATE, INSERT, UPDATE, DELETE et DROP▲
L'exécution d'une requête ne retournant pas d'informations (create, insert, update, delete ou drop) se décompose en deux parties :
- déclaration de la requête dans une variable
- exécution de la requête sur une base précise. Par défaut, c'est la première du xgql.properties qui est prise en compte
Si ces deux étapes ne sont pas respectées et que la requête est directement inclus dans la balise d'exécution, le script ne pourra pas lancer cette opération.
Création d'une table :
<
xgql
:
var
name
=
"create"
>
CREATE TABLE testXGQL (id integer, name varchar(20))</
xgql
:
var>
<
xgql
:
execute
name
=
"create"
connectionId
=
"myHsql"
/>
Insertion de données :
<
xgql
:
var
name
=
"insert1"
>
INSERT INTO testXGQL VALUES (1, 'test 1')</
xgql
:
var>
<
xgql
:
execute
name
=
"insert1"
connectionId
=
"myHsql"
/>
Suppression de données :
<
xgql
:
var
name
=
"delete"
>
DELETE FROM testXGQL WHERE id=2</
xgql
:
var>
<
xgql
:
execute
name
=
"delete"
connectionId
=
"myHsql"
/>
Mise à jour de données :
<
xgql
:
var
name
=
"delete"
>
UPDATE testXGQL SET id=4, name='test 4' WHERE id=3</
xgql
:
var>
<
xgql
:
execute
name
=
"delete"
connectionId
=
"myHsql"
/>
Suppression de la table :
<
xgql
:
var
name
=
"drop"
>
DROP TABLE testXGQL</
xgql
:
var>
<
xgql
:
execute
name
=
"drop"
connectionId
=
"myHsql"
/>
7-3. SELECT▲
7-3-1. Traitement de requête▲
Une requête de sélection se réalise de la même que les requêtes déjà vues précédemment, par le xgql:execute. La gestion des éléments retour se fait par le biais du xgql:row et du xgql:column.
<
xgql
:
var
name
=
"select"
>
SELECT * FROM testXGQL</
xgql
:
var>
<
xgql
:
execute
name
=
"select"
connectionId
=
"myHsql"
>
<
xgql
:
row>
<
xgql
:
var
name
=
"id"
>
<
xgql
:
column
name
=
"id"
wrap
=
"false"
/>
</
xgql
:
var>
</
xgql
:
row>
</
xgql
:
execute>
Le xgql:row définit le bloc sur lequel le script va itérer pour chaque tuple résultat de la requête.
xgql:column indique, via l'attribut name, quel est le nom colonne dont on souhaite obtenir la valeur. L'attribut wrap définit le format de cette sortie. Si wrap est à true, la valeur sera renvoyée dans une balise du nom de la colonne, sinon, c'est uniquement la valeur qui est renvoyé.
Dans l'exemple précédent,
<
xgql
:
column
name
=
"id"
wrap
=
"false"
/>
renvoie la valeur de l'id, alors que
<
xgql
:
column
name
=
"id"
wrap
=
"true"
/>
renvoie
<id>
value</id>
En fonction du type de sortie ou du traitement choisi, il est donc possible de générer de simples données textes ou un flux XML depuis une ou plusieurs bases de données. Exemple de sortie en texte :
<
xgql
:
var
name
=
"select"
>
SELECT * FROM testXGQL</
xgql
:
var>
<
xgql
:
execute
name
=
"select"
connectionId
=
"myHsql"
>
<result>
<
xgql
:
row>
<
xgql
:
var
name
=
"id"
><
xgql
:
column
name
=
"id"
wrap
=
"false"
/></
xgql
:
var>
<
xgql
:
var
name
=
"test"
><
xgql
:
column
name
=
"name"
wrap
=
"false"
/></
xgql
:
var>
Id is <b>
$id</b>
and value is <b>
$test</b><br/>
</
xgql
:
row>
</result>
</
xgql
:
execute>
7-3-2. Branche conditionnelle▲
Un peu comme le xgql:if, le branchement conditionnel est possible sur le xgql:execute avec la balise xgql:norow. Le bloc d'instruction de cette balise est interprété si la requête ne renvoie aucun résultat.
<
xgql
:
var
name
=
"select"
>
SELECT * FROM testXGQL</
xgql
:
var>
<
xgql
:
execute
name
=
"select"
connectionId
=
"myHsql"
>
<
xgql
:
row>
<
xgql
:
var
name
=
"id"
><
xgql
:
column
name
=
"id"
wrap
=
"false"
/></
xgql
:
var>
</
xgql
:
row>
<
xgql
:
norow>
Pas de resultat</
xgql
:
norow>
</
xgql
:
execute>
Il ne peut pas y avoir plusieurs instructions xgql:row dans le même xgql:execute. Le résultat du xgql:execute est du XML. Les données sont donc pré-formatées.
7-4. Travailler sur les données provenant des bases relationelles▲
Les bases relationnelles constituent bien sûr un datasource.
Lors de l'exécution d'un SELECT, on constate que le résultat est formaté directement en XML.
Il est donc possible d'encapsuler ce résultat dans une variable et de manipuler le XML obtenu grâce à du XQuery comme nous l'avons vu précédement.
Cela signifie également qu'il est très facile d'interpoler des données provenant des sources de données XML avec les données provenant de sources relationnelles.
8. Les extensions de langage▲
XGQL reste un langage très ouvert au travers de nombreuses extensions fournies ou non en natif.
Par exemple, l'extension web est fournie en natif avec la version 2.0, incluant toute une série d'instructions supplémentaires pour la gestion du web (cookies, sessions, etc.)
Pour inclure de nouvelles extensions, il suffit de le déclarer de la façon suivante :
<
xgql
:
extension
name
=
"SaxParserExtnExample"
package
=
"my.own.package"
/>
name est le nom de l'extension et l'attribut package indique le nom du package de l'extension.
Par défaut, le nom du package est 'org.symeria.xgql.parser.extension'
Il existe de nombreuses extensions de langage, tel que XGQL:DB2XML qui va rendre transparente la gestion de données XML dans un base de données relationnelles.
9. Les librairies▲
Nous avons vu précédemment qu'il était possible de réaliser des procédures pour simplifier et factoriser le code. Dans un souci de rentabilité, il est assez possible d'importer des librairies XGQL :
<
xgql
:
datasource>
C:Documents and Settings/yourpath/SWAS_XGQL/webapps/XGQL/myLib.xgq</
xgql
:
datasource>
Les librairies peuvent être accédées aussi par http et ftp.
10. XGQL et le web▲
XGQL dans sa version SWAS (API XGQL, serveur Jetty et base Hsql, le tout préconfiguré pour fonctionner en servlet) s'adapte au fonctionnalité web, avec la gestion :
- des cookies
- des requests
- des sessions
Néanmoins, l'utilisation de XGQL sous cette forme n'est pas la plus optimum et n'est pas recommandée pour la réalisation de sites complexes ou professionnels.
10-1. Cookies▲
Création d'un cookie :
<
xgql
:
cookie
id
=
"test"
expiration
=
"100000"
>
MyCookie</
xgql
:
cookie>
Récupération de la valeur d'un cookie:
<
xgql
:
cookie
id
=
"test"
/>
A ce niveau, la valeur est juste lue. Pour être traitée, elle doit être placée dans une variable.
10-2. Requests▲
Récupération d'une valeur passée en reqests :
<
xgql
:
request
name
=
"aRequestKeyName"
/>
10-3. Sessions▲
Création d'une valeur en session :
<
xgql
:
session
name
=
"aSessionKeyName"
>
My session Value</
xgql
:
session>
Récupération de la valeur en session:
<
xgql
:
session
name
=
"aSessionKeyName"
/>
A ce niveau, la valeur est juste lue. Pour être traitée, elle doit être placée dans une variable.
11. Conclusion▲
En conclusion, il n'y aura plus qu'une chose à préciser, mis à part ce petit détail : "Où trouver les dernières distributions XGQL ?"
Sur le site officiel XGQL est à l'adresse suivante XGQL.
Différentes versions de l'API XGQL y sont disponibles (API, source, SWAS, etc.) ainsi que de nombreux exemples.