Aller au contenu

%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.