%HANDLER
Traiter un document par lots
Remplace la variable de réception de XML-INTO (ou DATA-INTO) par une procédure qui reçoit les éléments du document par lots, sans avoir à tout garder en mémoire.
Syntaxe
XML-INTO %HANDLER(procédure : zone-de-liaison) %XML(document : options)
DATA-INTO %HANDLER(procédure : zone-de-liaison) %DATA(document : options) %PARSER(analyseur)
procédure- La procédure appelée à chaque lot. Elle reçoit la zone de liaison, un tableau d'éléments dont la dimension fixe la taille des lots, et le nombre d'éléments réellement remplis (passé par valeur). Elle renvoie un entier.
zone-de-liaison- Une variable de votre programme, transmise telle quelle à chaque appel : c'est là qu'on cumule les totaux.
- Résultat
- %HANDLER ne renvoie rien. C'est la procédure qui retourne un entier à XML-INTO : 0 pour continuer.
À quoi ça sert
Un fichier XML de plusieurs milliers de lignes ne tient pas dans un tableau de taille fixe. Avec %HANDLER, XML-INTO lit le document au fil de l'eau et appelle votre procédure toutes les N occurrences de l'élément répété : on totalise, on écrit en base, on affiche, puis le lot suivant remplace le précédent.
Exemple 1 : Cumuler les soldes de cinq clients par lots de deux
**free
// %HANDLER : XML-INTO confie les elements par lots a une procedure.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-ds client_t qualified template;
numcli packed(5:0);
nom varchar(20);
solde packed(9:2);
end-ds;
// Zone de communication : passee par XML-INTO a chaque appel du gestionnaire
dcl-ds bilan qualified inz;
nb_lots int(10);
nb_cli int(10);
total packed(11:2);
end-ds;
dcl-s doc varchar(600);
doc = '<clients>'
+ '<client><numcli>100</numcli><nom>Dupont SA</nom><solde>1250.50</solde></client>'
+ '<client><numcli>200</numcli><nom>Martin et fils</nom><solde>0</solde></client>'
+ '<client><numcli>300</numcli><nom>Leroy SARL</nom><solde>-320.00</solde></client>'
+ '<client><numcli>400</numcli><nom>Bernard Transports</nom><solde>98000.00</solde></client>'
+ '<client><numcli>500</numcli><nom>Petit Atelier</nom><solde>45.10</solde></client>'
+ '</clients>';
xml-into %handler(traiter : bilan) %xml(doc : 'case=any path=clients/client');
snd-msg 'Lots recus : [' + %char(bilan.nb_lots) + ']';
snd-msg 'Clients : [' + %char(bilan.nb_cli) + ']';
snd-msg 'Total : [' + %char(bilan.total) + ']';
*inlr = *on;
// Appelee par XML-INTO pour chaque lot de 2 clients au plus
dcl-proc traiter;
dcl-pi *n int(10);
comm likeds(bilan);
clients likeds(client_t) dim(2) const;
nombre int(10) value;
end-pi;
dcl-s i int(10);
comm.nb_lots += 1;
snd-msg 'Lot ' + %char(comm.nb_lots) + ' : ' + %char(nombre) + ' client(s)';
for i = 1 to nombre;
comm.nb_cli += 1;
comm.total += clients(i).solde;
endfor;
return 0; // 0 = continuer
end-proc;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Lot 1 : 2 client(s)
Lot 2 : 2 client(s)
Lot 3 : 1 client(s)
Lots recus : [3]
Clients : [5]
Total : [98975.60]
L'option path=clients/client désigne l'élément répété. Le tableau du paramètre clients a 2 éléments : la procédure est donc appelée 3 fois (2, 2 puis 1 client). La zone bilan, passée en deuxième paramètre de %HANDLER, garde le cumul entre les appels. Le total, 98975.60, est la somme des cinq soldes.
Exemple 2 : Arrêter la lecture
**free
// %HANDLER : le gestionnaire peut arreter la lecture en renvoyant une valeur non nulle.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-ds client_t qualified template;
numcli packed(5:0);
nom varchar(20);
solde packed(9:2);
end-ds;
// Zone de communication : passee par XML-INTO a chaque appel du gestionnaire
dcl-ds bilan qualified inz;
nb_lots int(10);
nb_cli int(10);
total packed(11:2);
end-ds;
dcl-s doc varchar(600);
doc = '<clients>'
+ '<client><numcli>100</numcli><nom>Dupont SA</nom><solde>1250.50</solde></client>'
+ '<client><numcli>200</numcli><nom>Martin et fils</nom><solde>0</solde></client>'
+ '<client><numcli>300</numcli><nom>Leroy SARL</nom><solde>-320.00</solde></client>'
+ '<client><numcli>400</numcli><nom>Bernard Transports</nom><solde>98000.00</solde></client>'
+ '<client><numcli>500</numcli><nom>Petit Atelier</nom><solde>45.10</solde></client>'
+ '</clients>';
monitor;
xml-into %handler(traiter : bilan) %xml(doc : 'case=any path=clients/client');
snd-msg 'XML-INTO termine normalement';
on-error;
snd-msg 'XML-INTO interrompu, statut ' + %char(%status);
endmon;
snd-msg 'Lots recus : [' + %char(bilan.nb_lots) + ']';
snd-msg 'Clients : [' + %char(bilan.nb_cli) + ']';
snd-msg 'Total : [' + %char(bilan.total) + ']';
*inlr = *on;
// Appelee par XML-INTO pour chaque lot de 2 clients au plus
dcl-proc traiter;
dcl-pi *n int(10);
comm likeds(bilan);
clients likeds(client_t) dim(2) const;
nombre int(10) value;
end-pi;
dcl-s i int(10);
comm.nb_lots += 1;
snd-msg 'Lot ' + %char(comm.nb_lots) + ' : ' + %char(nombre) + ' client(s)';
for i = 1 to nombre;
comm.nb_cli += 1;
comm.total += clients(i).solde;
endfor;
if comm.nb_lots = 2;
return 1; // valeur non nulle : on arrete
endif;
return 0; // 0 = continuer
end-proc;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Lot 1 : 2 client(s)
Lot 2 : 2 client(s)
XML-INTO interrompu, statut 351
Lots recus : [2]
Clients : [4]
Total : [98930.50]
Au deuxième lot, la procédure renvoie 1. XML-INTO s'arrête alors avec une erreur de statut 351, que le monitor intercepte : le troisième lot n'est jamais livré et le total ne compte que 4 clients.
Le piège
Renvoyer autre chose que 0 n'est pas un arrêt propre. Dès que le gestionnaire retourne une valeur non nulle, XML-INTO se termine sur l'erreur de statut 351 (message RNQ0351, « une erreur d'analyse syntaxique XML a été détectée »). Si le programme n'a pas de monitor, il s'arrête sur cette erreur.
Autre point : la zone de liaison doit être initialisée. Dans l'exemple, une structure sans inz a d'abord fait échouer le programme (erreur de données décimales, MCH1202) avant le premier lot.