Requêtes XQuery – Application xml

By 21 March 2012

Requêtes XQuery – Chapitre 7

Dans cette partie consacrée aux requêtes XQuery, qui devront fournir des résultats ABC, nous nous proposons de présenter notre travail de façon graduelle.
Nous débuterons par une requête élémentaire et tenterons de terminer en fin de chapitre par une requête fournissant un résultat ABC.
Nous utiliserons des requêtes de type FLWOR.

1-Produire une liste de clients.

Une première requête simple consiste à produire la liste des clients.

for $client in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)/ABC/client return
<p>{($client/@nom)}</p>

Dans la première ligne, nous déclarons la variable « client » en la faisant précéder par le signe $, soit « $client ».
La variable « $client » est précédée de la clause FOR.
FOR lance une itération qui permet à la requête FLWOR de multiples évaluations (récursives). La fonction « doc » ouvre le document sur lequel portera la requête.
(“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)/ABC/client
Pour accéder au document, il est fait usage d’une « path expression ».
Une « path expression » permet de sélectionner les éléments ou attributs nécessaires.

Le point de départ en est l’élément root du file system « / », puis le répertoire « home », puis le répertoire « jean », puis le répertoire « Mémoire_ulb_2009 », puis le répertoire « group_21juin » et enfin le fichier « abc_avril27jn_id01.xml », puis la racine « / ABC » du fichier, puis la séquence « client ».
Nous lions la variable $client au premier élément de la séquence « client » dont le « context node » est « ABC ».
La boucle induite par FOR évaluera chacune des valeurs prises par chacun des éléments de la séquence « client ».
La clause « return » envoie un élément d’information à chaque itération de la requête. Le résultat demandé est la valeur prise par l’attribut « nom » de l’élément « client ». A chaque évaluation, « return » enverra le nom d’un client.

Les évaluations itératives de « for » cesseront lorsqu’aura été évalué le dernier élément « client ».
<p>{($client/@nom)}</p>
Nous utilisons un « constructor » XML, afin de créer un élément <p/>, et donc un résultat de requête sous forme XML.
Le résultat en est le suivant:

<?xml version=”1.0″ encoding=”UTF-8″?> <p nom=”jaeger”/>
<p nom=”cairelli”/>
<p nom=”communication”/>

Chaque instanciation du résultat est un élément <p/>.
Nous pouvons modifier cette requête de façon à obtenir un arbre XML, comportant donc un élément racine, et des éléments <p> ne contenant que la valeur de l’attribut « nom ».
Nous choisissons de nommer l’élément racine <requete/>.
L’entièreté de la requête est incorporée dans les balises <requete> </requete>

<requete>
{
for $client in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)/ABC/client return
<p>{data($client/@nom)}</p>
} </requete>

Afin de ne conserver que la valeur atomique de l’attribut, nous faisons appel à la fonction « data » qui permet d’extraire les valeurs atomiques d’éléments et attributs.
<p>{data($client/@nom)}</p>
Le résultat est un arbre XML comportant l’élément racine « requête » parent de trois éléments <p/>. Notons que seuls les noms des trois clients apparaissent.

<?xml version=”1.0″ encoding=”UTF-8″?> <requete>
<p>jaeger</p>
<p>cairelli</p>
<p>communication</p>
</requete>

Nous utiliserons les « constructors » XML pour toutes les requêtes suivantes.
Les liens.
Nous devons pouvoir établir des liens entre éléments du document XML, liens équivalents à ceux définis dans les représentations par modèle hiérarchique ou ERD.
But de la requête: afficher pour chaque « activite » les « familles_cout » qui la composent.
<requete_lien>
{
for $in in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)/ABC

for $akty in $in/activite
return
<activite>
<nom_activite>{data($akty/@nom_activite)}</nom_activite>
{
for $famy in $in/famille_cout[@id_famille_cout=$akty/composition_activite/@id_famille_kout]
return
<famille_cout> {data($famy/@nom_famille)}</famille_cout>
} </activite>
} </requete_lien>

Un lien est à établir entre les « éléments » « activite » et « famille », par comparaison des attributs communs à « activite » et « famille ».
Pour l’élément « activite », il s’agit de l’attribut « id_famille_kout » (dans le « path » « ABC/ activite/composition _activite »).
Pour l’élément « famille cout », il s’agit de l’attribut « id_famille_cout » (dans le « path » « ABC/ famille_cout ».
Les valeurs que prennent ces attributs sont: « fam »1, « fam2 », « fam3 », « fam4 », « fam5 », « fam6 », « fam7 » et « fam8 ».
L’évaluation s’opérera en comparant un attribut « fam1 » trouvé dans un élément « activite » aux attributs « fam… » des éléments « famille_cout »; lorsque l’attribut « fam1 » sera trouvé en « famille_cout », la valeur de l’attribut « nom_famille » de cet élément « famille_cout » sera affichée.

Pour l’élément « activite » dont l’attribut « id_activite » = “act1”, les familles de coût figurant dans l’élément « composition_activite » correspondant aux valeurs prises par l’attribut « id_famille _kout » sont: « fam1 » et « fam2 ».
Le résultat affiché pour cet élément devrait être « fam1_publicite » et « fam2_bureau ». D’autres résultats seront affichés: nous ne filtrons pas
Que fait la requête?
La première boucle FOR évalue à partir du « context node » ABC le premier élément de la séquence « activite » et le lie à la variable « $akty ».

La clause « return » en restitue la valeur de l’attribut « nom_activite ».
Puis, la boucle FOR contenue dans « return » sélectionne à partir du « context node » « ABC », le premier élément de la séquence « famille_cout » et le lie à la variable « $famy » si la condition suivante est respectée.
La valeur de l’attribut « id_famille_cout » (de l’élément « famille_cout » traîté) est comparée à celle prise par l’attribut « id_famille_kout » du premier élément « composition_activite » de l’élément
« activite » lié à la variable « $akty ».
Lorsque la comparaison est positive, la valeur de l’attribut « nom_famille » de l’élément « famille_cout » est affichée.
La même itération se reproduit pour la « composition_activite » suivante de la variable « $akty », et ce jusqu’à la dernière « composition_activite» de l’ « activite » traitée.

Ensuite, retour à la première boucle FOR, qui reproduit les mêmes itérations pour le second élément de la séquence « activite », et ce jusqu’à ce qu’il n’y ait plus d’élément non traité dans la séquence
« activite ».
Le résultat figure ci-dessous.

<?xml version=”1.0″ encoding=”UTF-8″?>
<requete_lien>
<activite> <nom_activite>act1_communication</nom_activite> <famille_cout>fam1_publicite</famille_cout> <famille_cout>fam2_bureau</famille_cout>
</activite>
<activite> <nom_activite>act2_demarchage</nom_activite> <famille_cout>fam2_bureau</famille_cout>
<famille_cout>fam4_formation_documentation</famille_cout>
</activite>
<activite> <nom_activite>act3_logistique</nom_activite> <famille_cout>fam3_stock</famille_cout> <famille_cout>fam7_outil_production</famille_cout>
</activite> <activite>
<nom_activite>act4_transport</nom_activite>
<famille_cout>fam6_transport</famille_cout>
</activite>
<activite> <nom_activite>act5_production</nom_activite>
<famille_cout>fam4_formation_documentation</famille_cout> <famille_cout>fam7_outil_production</famille_cout>
</activite>
<activite> <nom_activite>act6_comptabilite_abc</nom_activite> <famille_cout>fam2_bureau</famille_cout>
<famille_cout>fam4_formation_documentation</famille_cout> <famille_cout>fam5_honoraires</famille_cout>
</activite> <activite>
<nom_activite>act7_telecom</nom_activite>
<famille_cout>fam8_telecom</famille_cout>
</activite>
</requete_lien>

Notons que nous obtenons un arbre XML ayant pour élément racine </requete_lien>, qui a pour éléments enfants les éléments </activite> lesquels contiennent les éléments </nom_activite> et </famille_cout>.

2-Effectuer des opérations arithmétiques.

Nous devons effectuer, pour obtenir des résultats ABC, des opérations de calcul. Ce sont des opérations élémentaires, sommer, multiplier et diviser.
– Sommer fait usage de la fonction « SUM », qui est une fonction d’agrégation portant sur une séquence de résultats.
– La multiplication est liée à l’opérateur « * »
– La division a pour opérateurs « div » et « idiv ». Nous utiliserons « div ».

3-Sommer les charges .

Cette requête devrait nous retourner la somme des « montant_htva_total ». Nous reproduisons le fragment de document XML ci-dessous.

<charge_indirecte id_chargeindirecte=”fact001″ montant_htva_total=”2000″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact005″ montant_htva_total=”2401″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact011″ montant_htva_total=”710″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact015″ montant_htva_total=”623.85″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact016″ montant_htva_total=”310″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact028″ montant_htva_total=”4562″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact031″ montant_htva_total=”2100″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact032″ montant_htva_total=”2542″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact054″ montant_htva_total=”600″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact055″ montant_htva_total=”240″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact056″ montant_htva_total=”211″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact062″ montant_htva_total=”118.7″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact071″ montant_htva_total=”560″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact072″ montant_htva_total=”422″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact075″ montant_htva_total=”58″>
… </charge_indirecte>
<charge_indirecte id_chargeindirecte=”fact100″ montant_htva_total=”74.6″>
… </charge_indirecte>

La requête:

<requete_somme>
{
for $chargeind in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”) //charge_indirecte
return
<Eur> {sum($chargeind/@montant_htva_total)} </Eur>
} </requete_somme>

Cette requête comporte une erreur.
Nous la présentons car le résultat, qui n’est pas celui attendu, illustre très bien la notion de séquence de résultats.
Fonctionnement de la requête.
La variable « $chargeind » est liée à la séquence « charge_indirecte ».
Une boucle FOR parcourt une à une les instantiations de la séquence et les passe à « $chargeind » . Return affiche à chaque itération l’attribut « charge_indirecte/@montant_htva_total » de la variable « $chargeind ».
Le résultat retourné.

<?xml version=”1.0″ encoding=”UTF-8″?>
<requete_somme> <Eur>2000</Eur> <Eur>2401</Eur> <Eur>710</Eur> <Eur>623.85</Eur> <Eur>310</Eur> <Eur>4562</Eur> <Eur>2100</Eur> <Eur>2542</Eur> <Eur>600</Eur> <Eur>240</Eur> <Eur>211</Eur> <Eur>118.7</Eur> <Eur>560</Eur> <Eur>422</Eur> <Eur>58</Eur> <Eur>74.6</Eur>
</requete_somme>

Nous constatons que le résultat n’est pas un total, mais une séquence des nombres qui auraient du être sommés.
La cause en est que nous avons intégré la fonction « SUM » dans la séquence de génération de nombres, alors que la séquence aurait dû se produire dans « SUM », « SUM » étant une fonction d’agrégation.
Si nous avions appelé la fonction « data » au lieu de la fonction « SUM », le résultat aurait été identique.
La requête doit être modifiée de façon à ce que les itérations FOR se produisent au sein de « SUM ».
Nous invoquons dès lors « SUM » au début de la requête

<requete_somme>
{ sum(
for $chargeind in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”) //charge_indirecte
return
<Eur> {data($chargeind/@montant_htva_total)} </Eur>
) } </requete_somme>

Nous obtenons le résultat attendu: la somme est de 17533,15 (Euro).

<?xml version=”1.0″ encoding=”UTF-8″?> <requete_somme>17533.15</requete_somme>

4-Calculer le coût d’une unité d’oeuvre (d’activité).

Dans cette nouvelle requête, nous voulons calculer le coût d’une unité d’oeuvre pour une activité déterminée.
Nous choisissons l’activité5, « act5_production ».
La démarche suivie.

1) Calculer le coût total de l’activité choisie.
– Filtrer les éléments « activite ».
– Les lier aux éléments « famille_cout ».
– Lier les éléments « famille_cout » aux éléments « charge_indirecte/imputation ».
2) Sommer la quantité de mesurages correspondant à l’activité choisie.
3) Calculer et sommer.

-Le calcul de notre requête peut se résumer par:
SUM « montant_htva_impute » * « proportion_cf » * « proportion » div SUM « quantite » (de mesurages).
La requête se présente comme suit:

<requete_calcul_unite_oeuvre>
{
sum(
for $in in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)/ABC, $akty in $in/activite[@id_activite=”act5″],
$compoakt in $akty/composition_activite,
$famy in $in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille, $pcmn in $in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
return <activite>{data($pcmn/@montant_htva_impute
*$famy/@proportion_cf
*$compoakt/@proportion
div
sum(
for $mesur in $in/client/commande/mesurage[@id_aktivite=”act5″]
return <div>{data($mesur/@quantite)}</div>)
)}
</activite>
)}
</requete_calcul_unite_oeuvre>

Fonctionnement de la requête.
Nous utilisons des boucles FOR; notre point de départ sera le « context node » ABC.
La variable « $akty » est liée au premier élément de la séquence « activite » qui est sélectionné si le prédicat « id_activite » = « act5 » est respecté.
Si le prédicat n’est pas respecté, par itération le second élément est examiné, le troisième, jusqu’au dernier si nécessaire.
La variable « $compoact » est liée au premier élément de la séquence « composition_activite » dont le « context node » est $akty (qui respecte « act5 »).
La variable « $famy » est liée au premier élément de la séquence « famille_cout » si un lien est établi.
Nous établissons un lien avec l’élément « activite » par comparaison des valeurs des attributs « famille_cout/@id_famille_cout » et « activite/composition_activite/@id_famille_kout ».

Le lien est établi si il y a concordance, sinon, il y a itération vers le second élément de la séquence « famille_cout », évaluation pour lien, et ce jusqu’au dernier si nécessaire.
La variable « $pcmn » accède au premier élément « imputation » du « context node » « charge _indirecte » .
Comme ci-dessus, un lien est établi avec la variable « $famy » par comparaison des valeurs des attributs « id_pcmn_imputation » à « id_pcmn_fam ».
Une itération se produit pour le second élément « imputation » , etc, tant qu’un lien n’a pas été établi.
Return reçoit la valeur de l’attribut « montant_htva_impute » lorsqu’un lien est établi ($pcmn) et traite le premier résultat en le multipliant par la valeur de l’attribut « $famy/@proportion_cf » multiplié par la valeur de l’attribut « $compoakt/@proportion ».

<activite>{data($pcmn/@montant_htva_impute *$famy/@proportion_cf
*$compoakt/@proportion

Nous devons diviser ce résultat par la somme des quantités de mesurages correspondant. Return comprend une boucle FOR.
La variable « $mesur » est liée aux éléments de la séquence « mesurage » du « context node »
« commande », dont la valeur de l’attribut « id_aktivite » respecte le prédicat « id_aktivite » = « act5 ».
Cette boucle se produit à l’intérieur d’un « SUM » qui somme les valeurs prises par l’attribut « quantite » qui sont retournées.

div
sum(
for $mesur in $in/cient/commande/mesurage[@id_aktivite=”act5″] return
<div>{data($mesur/@quantite)}</div>)

Le premier résultat « montant_htva_impute » * « proportion_cf » * « proportion » est ainsi divisé par la somme des « quantite ».
Après cette opération, la boucle retourne parcourir et comparer les éléments « imputation », puis retourne vers les éléments « composition_famille », et enfin retourne vers les éléments
« composition_activite » jusqu’à l’épuisement des éléments « activite ».
Après le dernier « return », la séquence de résultats est sommée. Le résultat de la requête:

<?xml version=”1.0″ encoding=”UTF-8″?> <requete_calcul_unite_oeuvre>18.17860066006601</requete_calcul_unite_oeuvre>

Soit 18,178 (Euro) le coût d’une unité d’oeuvre de l’activité « act5_production ».
Nous avons voulu vérifier au moyen d’un tableur (sous Linux).
Nous y avons rapporté les données rencontrées par la requête qui parcours le fichier XML.

mes004 8 fam4 0,34 612300 1 157,85 53,67 0,71
mes008 8,5 fam4 0,34 612300 1 560 190,4 2,51
mes010 6 fam7 0,73 601300 1 850 620,5 8,19
mes012 10 fam7 0,73 611130 1 422 308,06 4,07
mes023 2 fam7 0,73 613540 1 0 0
mes018 8 fam7 0,73 630220 0,8 350 204,4 2,7
mes020 7,25
mes026 10
mes031 7
mes033 9
Valeur de 1 unité d’oeuvre de l’activité5 18,18
75,75

Les mesurages portant sur l’activité5 sont au total de 75,75 unités.
L’activité 5 est composée des familles fam4 qui intervient à 34% et fam5 qui intervient à 73%. La famille4 est constituée du poste pcmn 612300 qui intervient à 100% dans la famille4.
Nous trouvons dans charge_indirecte/imputation deux « montants_htva_impute », soit 157,85 (Euro) et 560 (Euro).
157,85 * 1 * 0,34 = 53,67 (Euro) 560 * 1 * 0,34 = 190,4 (Euro)
Le même raisonnement est à appliquer à la famille7.

Détaillons la dernière ligne: le poste pcmn 630220 qui constitue la famille7: le montant de 350 (Euro) est imputé; il est multiplié par 80% (intervention dans la famille) et est à nouveau multiplié par 73%, intervention de la famille dans l’activité5, soit 350 * 0,73 * 0,8 = 204,4 (Euro)
Chacun de ces produits sont divisés un à un par le total des unités mesurées, soit 75,75 .
Pour la première ligne: 53,67 / 75,75 = 0,71 (Euro)
La dernière ligne: 204,4 /75,75 = 2,7 (Euro)

La somme de ces quotients est bel et bien de 18,18 (Euro) , résultat fourni par la requête.
Ayant pu vérifier la justesse du résultat de la requête, nous calculons encore le coût d’une unité d’oeuvre de l’activité « act4_transport », et en retenons la valeur pour la suite: 2,652 (Euro).
<?xml version=”1.0″ encoding=”UTF-8″?> <requete_calcul_unite_oeuvre>2.6521739130434785</requete_calcul_unite_oeuvre>

5-Calculer le coût indirect d’une commande déterminée.

Nous souhaitons obtenir le coût indirect pour une commande précise.
La démarche suivie.
Nous réutilisons la démarche précédente, mais le point de départ est une commande choisie.

1) Sélectionner une commande et calculer le coût total des activités utilisées. – Filtrer les éléments « commande ».
– Sélectionner les éléments « activite » utilisés par la commande choisie. – Les lier aux éléments « famille_cout ».
– Lier les éléments « famille_cout » aux éléments « charge_indirecte/imputation ».
2) Sommer la quantité de mesurages correspondant aux activités traitées.
3) Calculer et sommer.

En cours d’élaboration de cette requête, est apparue une erreur du fait de la nature différente des activités, erreur que nous détaillons.
Prenons comme exemple la commande ayant le « id_commande » com003.
Cette commande comporte deux mesurages, l’un concernant l’activité « id_aktivite » = « act4 »,
l’autre, l’activité « id_aktivite » = « act5 ».
Les unités d’oeuvre utilisées pour ces deux activités sont fondamentalement différentes. l’activité4 transport a pour unité de mesure le kilomètre parcouru.

L’activité5 se mesure elle en heure de production.
Ce tableau synthétise l’information telle qu’elle sera traitée par la requête.
Nous imaginons qu’activité4 (act4) et activité5 (act5) ont respectivement un coût de 600 (Euro) et 1000 (Euro).
La colonne « produit » doit son appellation au fait qu’il s’agit du résultat de l’opération: « montant_htva _impute » * « proportion_cf » * « proportion ».

Du fait de la nature différente des unités d’oeuvre, nous aurons beaucoup plus de kilomètres que d’heures prestées.
Nous avons 107 kilomètres (45 + 62) parcourus pour 13 heures de travail (6 + 7).
La requête sommera 120 unités mesurées, sans distinction quant à leur différence de nature.
Le calcul qui sera effectué pour calculer le coût d’une unité d’oeuvre sera: 600 (Euro) / 120 et 1000 (Euro) / 120, soit 5 (Euro) et 8,33 (Euro).

Ce qui est évidement faux.
L’opération à effectuer est de diviser l’activité4 par la somme d’unités s’y rapportant, et pratiquer de même pour l’activité5.
Pour l’activité4, 600 (Euro) / 107 = 5,61 (Euro) par unité d’oeuvre
Pour l’activité5, 1000 (Euro) / 13 = 76,92 (Euro) par unité d’oeuvre
La requête devra donc intégrer la possibilité de distinguer les différents types d’unité d’oeuvre possibles.

6-Calculer le coût indirect de la commande « com003 ».

Nous traiterons l’exemple qui consiste à afficher le coût indirect de la commande dont la valeur de « id_commande » est « com003 ».
Nous reproduisons le fragment du document XML ci-dessous.

<commande id_commande=”com003″ descriptif=”seconde commande” chiffre_affaire=”1852″>
<mesurage id_mesurage=”mes022″ id_aktivite=”act4″ date=”12 avril 2009″ quantite=”42″ unite_oeuvre=”kilometre”/>
<mesurage id_mesurage=”mes023″ id_aktivite=”act5″ date=”12 avril 2009″ quantite=”2″ unite_oeuvre=”heure_production”/>
<charge_directe id_charge_d=”fact0041″ id_pcmn=”601000″ montant_dir_htva_impute=”640″ quantite=”1″/>
<charge_directe id_charge_d=”fact9999″ id_pcmn=”620000″ montant_dir_htva_impute=”25″
quantite=”2″/>
</commande>

Nous utilisons comme base la requête précédente de calcul d’une unité d’oeuvre pour une activité donnée.
Nous y avons ajouté le prédicat nécessaire à parcourir le document XML à partir de la commande « com003 » .
La requête se présente comme suit.
<cout_indirect_commande>
{
sum(
for $in in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)//ABC, $commande in $in/client/commande[@id_commande=”com003″],
$akty in $in/activite[@id_activite=$commande/mesurage/@id_aktivite],
$compoakt in $akty/composition_activite,
$famy in $in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille, $pcmn in $in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
return <activite>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
sum(
for $uo in $in /client/commande/mesurage/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
sum(
for $uototal in $commande/mesurage/@quantite
return
<uo_total>{data ($uototal)}</uo_total>) )}</activite>

} </cout_indirect_commande>

Fonctionnement de la requête.
En boucle FOR, nous déclarons les variables.
La variable « $commande » est liée au premier élément de la séquence « commande » du « context node » ABC respectant le prédicat « id_commande » = « com003 ».
La variable « $akty » est liée au premier élément de la séquence « activite » qui est sélectionné si un lien peut être établi avec l’élément de la séquence « commande ».
Le lien est effectif si la comparaison des attributs « id_activite » de l’élément activité et de « id_aktivite » du premier élément de la séquence mesurage ayant pour « context node »
« $commande » abouti.
Si le lien n’est pas établi, une itération examine le second élément de la séquence « activite », etc…
La variable « $compoact » est liée au premier élément de la séquence « composition_activite » dont le « context node » est $akty (qui est liée à « $commande » ).
La variable « $famy » est liée au premier élément de la séquence « composition_famille » de la séquence « famille_cout » si un lien est établi.
Nous établissons un lien avec l’élément « activite » par comparaison des valeurs des attributs « famille_cout/@id_famille_cout » et « $compoakt/@id_famille_kout ».
Le lien est établi si il y a concordance, sinon, il y a itération vers le second élément de la séquence « famille_cout », pour une nouvelle évalucation.

La variable « $pcmn » accède au premier élément « imputation » du « context node » « charge_indirecte » .
Un lien est établi avec la variable « $famy » par comparaison des valeurs des attributs « imputation/@id_pcmn_imputation » à « $famy/@id_pcmn_fam ».
Une itération se produit pour le second élément « imputation » , etc…, tant qu’un lien n’a pas été établi.
Return fourni une séquence de résultats: « montant_htva_impute » multiplié par « proportion_cf » multiplié par « proportion » divisé par la somme de la valeur des attributs « mesurage/@quantite » sélectionnés.
Nous devons enfin multiplier ce résultat par la somme de mesurages « mesurage/@quantite » se rapportant à cette commande « com003 ».
Cette requête traitera les mesurages de la commande « com003 » identiquement, et générera l’erreur que nous évoquions ci-dessus.
Le résultat de la requête annonce un coût indirect de 446,234 (Euro) pour cette commande.
<?xml version=”1.0″ encoding=”UTF-8″?> <cout_indirect_commande>446.2341931548628</cout_indirect_commande>

7-IF THEN ELSE.

Lorsque nous examinons les mesurages de « com003 », nous voyons qu’ils sont deux. Le premier 42 unités (kilomètres) pour l’activité4 (transport).
Le second 2 unités (heure_production) pour l’activité5 (production).
Afin que ces deux activités soient traitées individuellement, nous avons utilisé IF THEN ELSE.
Nous avons 7 activités qui doivent être traitées individuellement, et devons proposer 7 traitements individuels.
Nous avons retenu la solution suivante.
Return sera suivi d’une expression IF posant comme condition que l’activité à traiter soit l’activité1. Si il s’agit bien de l’activité1, l’expression THEN autorise le calcul de la requête.

La différence du traitement appliqué par « Return » comparativement aux deux requêtes précédentes est que nous ne considérons plus les quantités de mesurage dans leur globalité, mais individuellement pour chaque activité.
Nous ajoutons donc un prédicat: « @id_aktivite=”act1″ » .
for « $uo » in « $in » /client/commande/mesurage/@quantite
devient
for « $uo » in « $in » /client/commande/mesurage[@id_aktivite=”act1″]/@quantite
return
if ($akty/@id_activite=”act1″)
then
<activite_1>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act1″]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act1″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>) )}</activite_1>
Si il ne s’agit pas de l’activité1, l’expression ELSE évalue s’il s’agit de l’activité2 au quel cas l’expression THEN autorise le traitement.
L’évaluation se fera sur base du prédicat « @id_aktivite=”act2″ »

else
if ($akty/@id_activite=”act2″) then
<activite_2>{data($ … etc…

Et ce répétitivement jusqu’à l’activité6 au terme de laquelle il ne reste plus comme dernière alternative que de traiter l’activité7.

else
<activite_7>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
sum(
etc
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_7>
) } </cout_abc_commande>

L’entièreté de cette requête est imbriquée dans SUM( ), afin de sommer la séquence de résultats. Nous reproduisons la requête complète ci-dessous.
<cout_indirect_commande>
{
sum(
for $in in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)/ABC, $commande in $in/client/commande[@id_commande=”com003″],
$akty in $in/activite[@id_activite=$commande/mesurage/@id_aktivite],
$compoakt in $akty/composition_activite,
$famy in $in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille, $pcmn in $in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
return
if ($akty/@id_activite=”act1″)
then <activite_1>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act1″]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act1″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>) )}</activite_1>
else
if ($akty/@id_activite=”act2″)
then <activite_2>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act2″]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act2″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>) )}</activite_2>
else
if ($akty/@id_activite=”act3″)
then <activite_3>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act3″]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act3″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_3>
else
if ($akty/@id_activite=”act4″)
then <activite_4>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act4″]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act4″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_4>
else
if ($akty/@id_activite=”act5″)
then <activite_5>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act5″]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act5″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_5>
else
if ($akty/@id_activite=”act6″)
then <activite_6>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act6″]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act6″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_6>
else
<activite_7>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion
div
sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act7″]/@quantite
return<uoeuvre>{data ($uo)}
</uoeuvre>)
*
sum(
for $uototal in $commande/mesurage[@id_aktivite=”act7″]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
)}</activite_7>
)
}
</cout_indirect_commande>
Le résultat généré est cette fois de 147,748 (Euro).
<?xml version=”1.0″ encoding=”UTF-8″?> <cout_indirect_commande>147.7485056679581</cout_indirect_commande>

8-Les « function » .

En procédant de la sorte, nous obtenons un résultat différent, mais au prix d’une requête longue (121 lignes) et complexe à lire.
Nous utiliserons les « functions » ou fonctions proposées par XQuery afin d’alléger le code. Le bloc suivant calculant la somme des mesurages pour une activité se répète à sept reprises.

sum(
for $uo in $in /client/commande/mesurage[@id_aktivite=”act1″]/@quantite return
<uoeuvre>{data ($uo)}</uoeuvre>)

Nous le transformons en « function ».
Une « function » comporte les parties suivantes:
– la déclaration de « function » suivie de son nom « declare function local: ici le nom ».
– les paramètres de la « function » et le type retourné par la « function » (entre parenthèses). – le corps de la « function » contenant les instructions de traitement.
Nous déclarons la « function » que nous nommons : « activite »:
declare function local:activite
Nous avons un seul paramètre qui est « act1 » ou « act2 », …, ou « act7 ».
La variable « $ak » que nous déclarons prendra comme argument un des sept « act… »
Ce paramètre est de type « atomic », et le résultat de la « function » sera également une valeur « atomic » (un nombre).
La déclaration de « function » complète est:
declare function local:activite($ak as xs:anyAtomicType?)as xs:anyAtomicType?
Le corps de la « function » est la partie de imbriquée dans SUM.

{ sum(
for $uo in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”) //client/commande/mesurage[@id_aktivite=$ak]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
}

La « function » complète ci-dessous:

declare function local:activite($ak as xs:anyAtomicType?)as xs:anyAtomicType? {
sum(
for $uo in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”) //client/commande/mesurage[@id_aktivite=$ak]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
};

Nous pouvons créer une seconde « function » calculant la somme des mesurage par activité pour une commande précise.

sum(
for $uototal in $commande/mesurage[@id_aktivite=”act7″]/@quantite return
<uo_total>{data ($uototal)}</uo_total>)

Nous nommons cette « function » « activite2 ».

declare function local:activite2($ak2 as xs:anyAtomicType?)as xs:anyAtomicType? {
sum(
for $uototal in doc(“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)// client/commande[@id_commande=”com003″]/mesurage[@id_aktivite=$ak2]/@quantite return
<uo_total>{data ($uototal)}</uo_total>)
};

XQuery permet qu’une « function » se trouve au sein d’un espace mémoire dédié ou bien dans la requête elle même; nous retenons cette seconde possibilité.
Les deux « functions » se trouvent en préambule de la requête.
Au sein de la requête, pour le calcul relatif à l’activité1, nous appelons la « function » « activite » par:
local:activite(“act1”)
et lui passons le paramètre « act1 »
et la seconde « function » qui reçoit le meme paramètre par:
local:activite2(“act1”)

Requêtes XQuery - Application xmlLa requête complète devient:
declare function local:activite($ak as xs:anyAtomicType?)as xs:anyAtomicType? {
sum(
for $uo in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”) //client/commande/mesurage[@id_aktivite=$ak]/@quantite
return
<uoeuvre>{data ($uo)}</uoeuvre>)
};
declare function local:activite2($ak2 as xs:anyAtomicType?)as xs:anyAtomicType?
{
sum(
for $uototal in doc(“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)// client/commande[@id_commande=”com003″]/mesurage[@id_aktivite=$ak2]/@quantite
return
<uo_total>{data ($uototal)}</uo_total>)
};
<cout_indirect_commande>
{
sum(
for $in in doc (“/home/jean/Mémoire_ulb_2009/group_21juin/abc_avril27jn_id01.xml”)/ABC, $commande in $in/client/commande[@id_commande=”com003″],
$akty in $in/activite[@id_activite=$commande/mesurage/@id_aktivite],
$compoakt in $akty/composition_activite,
$famy in $in/famille_cout[@id_famille_cout=$compoakt/@id_famille_kout]/composition_famille, $pcmn in $in/charge_indirecte/imputation[@id_pcmn_imputation=$famy/@id_pcmn_fam]
return
if ($akty/@id_activite=”act1″)
then <activite_1>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
local:activite(“act1”)
*
local:activite2(“act1″)
)}</activite_1>
else
if ($akty/@id_activite=”act2”)
then <activite_2>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
local:activite(“act2”)*local:activite2(“act2″)
)}</activite_2>
else
if ($akty/@id_activite=”act3”)
then <activite_3>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
local:activite(“act3”)*local:activite2(“act3″)
)}</activite_3>
else
if ($akty/@id_activite=”act4”)
then <activite_4>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
local:activite(“act4”)*local:activite2(“act4″)
)}</activite_4>
else
if ($akty/@id_activite=”act5”)
then <activite_5>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
local:activite(“act5”)*local:activite2(“act5″)
)}</activite_5>
else
if ($akty/@id_activite=”act6”)
then <activite_6>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
local:activite(“act6”)*local:activite2(“act6”)
)}</activite_6>
else <activite_7>{data($pcmn/@montant_htva_impute*$famy/@proportion_cf*$compoakt/@proportion div
local:activite(“act7”)*local:activite2(“act7″)
)}</activite_7>
)}
</cout_indirect_commande>
La requête est simplifiée, 85 lignes; si nous souhaitons modifier la méthode de calcul des quantités de mesurage, une seule modification de « function » sera nécessaire, alors qu’il aurait fallu modifier à sept reprises sans l’usage de « functions ».
Le résultat de cette requête est identique:
<?xml version=”1.0″ encoding=”UTF-8”?> <cout_indirect_commande>147.7485056679581</cout_indirect_commande>

9-Vérification du résultat.

Nous avons à nouveau souhaité vérifier le résultat.
Ayant déjà vérifié le coût d’une unité d’oeuvre pour l’activité5, nous vérifions celle de l’activité 4. Commande « com003 » utilise 42 unités d’oeuvre de l’activité4 (mesurage « mes022 »).
de tous les mesurages se rapportant à l’activité4 est de 483 unités d’oeuvre.
Nous obtenions précédement pour l’activité5 un coût d’unité d’oeuvre de 18,178 (Euro)

<?xml version=”1.0″ encoding=”UTF-8″?> <requete_calcul_unite_oeuvre>18.17860066006601</requete_calcul_unite_oeuvre>

et de 2,652 (Euro) pour l’activité4.
<?xml version=”1.0″ encoding=”UTF-8″?> <requete_calcul_unite_oeuvre>2.6521739130434785</requete_calcul_unite_oeuvre>
Pour la commande « com003 », 42 unités de l’activité4 sont utilisées: 2,652 * 42 = 111,384 (Euro). Pour l’activité5, où 2 unités d’oeuvre sont mesurées: 18,18 * 2 = 36,36 (Euro).
Sommons ces deux valeurs: 111,384 + 36,36 = 147,744 (Euro) soit le résultat fourni par la requête XQuery.

Lire le mémoire complet ==> (Application de la méthode Activity Based Costing, technologies XML)
Mémoire présenté en vue de l’obtention du grade de Licencié en Informatique et Sciences humaines
Université libre de Bruxelles, Faculté des sciences sociales politiques et économiques