Notes sur la version 2 et plus du moteur de script

Pour tirer parti des fonctionnalités de XPath 2, l'écriture de scripts avec la version 2 ou plus du moteur nécessite de la syntaxe supplémentaire. En général, toute variable déclarée est considérée comme une chaîne. Par conséquent, si vous voulez élaborer une instruction mathématique, vous devez déclarer explicitement le type de données des variables pour indiquer s'il s'agit d'entiers, de nombres ou de dates.

Remarque :
Sauf indication contraire, tous les exemples XPath de cette rubrique concernent la version 1 du moteur, autrement dit XPath 1. Des instructions qui fonctionnent pour XPath 1 ne fonctionneront pas nécessairement pour XPath 2. C'est particulièrement vrai pour l'exécution d'opérations mathématiques ; voir exemples ci-dessous.

Arithmétique sur les dates/heures

Les types de données XPath de date/heure et d'intervalle prennent en charge les opérations arithmétiques ("+", "-", "*" etc.) et les fonctions arithmétiques, qui peuvent être utilisées pour les calculs de temps de même que "1 + xs:integer(value)" est utilisé pour les calculs numériques.

Comparer des durées :

if ("(xs:dateTime(fn:current-dateTime()) - xs:dateTime($updateDateTimeX))
   ge xs:dayTimeDuration(concat('PT', BO/hoursBetweenStatisticsUpdate, 'H'))")
   goto 60;
end-if;

Comparer une date à une autre :

if ("xs:date(parm/endDate) < xs:date(parm/startDate)")
   terminate with error (11108, 11507 element='endDate');
end-if;

Comparer une date à la date du jour :

if ("xs:date(parm/startDate) <= xs:date($CURRENT-DATE)")
   terminate with error (11108, 11507 element='endDate');
end-if;

Calculer la fin du mois :

// covert to ISO
move "concat($year,'-',$mon2,'-01T00:00:00')" to $monthStart; 
 
// calculate
move "xs:dateTime($monthStart) + xs:yearMonthDuration('P1M') - xs:dayTimeDuration('P0DT1S')" 
  to $monthEnd;
 
// convert from ISO to OUAF
move "concat($year,'-',$mon2,'-',substring(string($monthEnd),9,2),'-23.59.59')" to $endDateTime;
Remarque :
Les formats XPath de date/heure/intervalle utilisent la norme ISO, qui nécessite une conversion vers/depuis les formats pris en charge dans Framework.

Comparer des dates/heures au format chaîne

Tout format chaîne de type ISO conserve la séquence YYYY MM DD HH MM SS, qui est complétée par des zéros. Indépendamment des séparateurs, ce format reste approprié pour des opérations de comparaison. En particulier, les valeurs de date/heure ayant le format Framework "YYYY-MM-DD.HH.MM.SS" sont utilisables avec "=" et "!=", ainsi qu'avec les opérateurs ">", ">=", "<" et "<=".

// retrieve framework date/time value
invokeBS 'CM-MAXMSRMT' using "CM-MAXMSRMT";
move "string(cm-MAXMSRMT/results[1]/measurementDateTime)" to $lastMsmtDT;
 
// construct another date/time
move "concat($year,'-01-01-00.00.00')" to $startDateTime;
 
// compare using string operators
if ("$lastMsmtDT >= $startDateTime")
    move "substring($lastMsmtDT,1,4)" to $latestMsrmtYear;

Convertir les dates/heures entre Framework et ISO

La conversion des dates/heures du format Framework au format ISO n'est nécessaire que pour l'arithmétique sur les dates/heures. Des comparaisons peuvent être effectuées directement avec le format Framework. La seule différence entre les formats de date/heure Framework et ISO réside dans les séparateurs :

Framework : "YYYY-MM-DD.HH.MM.SS"

ISO : "YYYY-MM-DDTHH:MM:SS"

Exemple de conversion du format Framework au format ISO :

move "concat(substring($ouafDT, 1, 10), 'T', translate(substring($ouafDT, 12),'.',':'))" to $isoDT;

Exemple de conversion du format ISO au format Framework :

move "concat(substring($isoDT, 1, 10), '.', translate(substring($isoDT, 12),':','.'))" to $ouafDT;

Arrondir une somme avec une précision de devise dynamique

Des devises différentes n'acceptant pas le même nombre de décimales, Framework fournit une API pour l'arrondi des montants monétaires en fonction de la devise.

move "parm/amount" to $qnty;
move "currency/decimals" to $decimals;
move "fn:round(xs:decimal($qnty) * math:exp10(xs:double($decimals))) 
  div math:exp10(xs:double($decimals))" to "parm/roundedAmount";

Boucle sur des séquences

Avec XPath2, une boucle for peut tourner sur une séquence d'entiers et non seulement sur une liste de noeuds.

L'exemple ci-dessous illustre une boucle sur une plage de mois. Il s'agit d'une construction génératrice de séquence dans XPath. La liste de noeuds XPath, dont nous sommes familiers, est juste un autre type de séquence.

for ($month in "1 to 12")

L'exemple ci-dessous illustre une boucle sur une plage d'années donnée en ordre décroissant :

for ($year in "fn:reverse(parm/startYear to parm/endYear)")
     move "concat($year,'-01-01-00.00.00')" to $startDateTime;
     move "concat($year,'-12-31-23.59.59')" to $endDateTime;
     ...   

L'exemple ci-dessous illustre une boucle sur une liste de noeuds utilisant "index", de façon à permettre l'accès à d'autres listes de noeuds.

for ($idx in "1 to count(parm/touData/touList)")
     move "parm/touData/touList[$idx]" to $tou;   // access any list with this index   

La syntaxe ci-dessus constitue une alternative élégante à la maintenance séparée des index et peut par exemple remplacer :

move “0” to $idx;
for ($item in "parm/touData/touList")
     move “1 + xs:integer($idx)” to $idx;

Remplissage de chaînes et formatage décimal

Ces possibilités sont utilisées avec des formats d'entrée particuliers ou pour le formatage des sorties. Elles s'appliquent au remplissage par des zéros, des espaces et autres.

L'exemple ci-dessous illustre le préfixage des composants de date/heure, par exemple pour obtenir "2010-01-02" au lieu de "2010-1-2".

move "substring(concat('0',string($month)), string-length(string($month)), 2)" to $mon2; 

L'exemple ci-dessous illustre le suffixage employé pour effectuer un alignement décimal avec remplissage par des zéros, pour obtenir par exemple "12,30" et "4,00" au lieu de "12,3" et "4". Cet exemple effectue trois opérations : arrondi à 2 décimales, insertion d'une marque décimale si nécessaire et remplissage par des zéros.

// round and zero-pad to 2 decimals
move "$item/amount" to $qty;
move "fn:round(xs:double($qty) * 100) div 100" to $qty;
move "string($qty)" to $qty;
move "concat(substring-before(concat($qty,'.'),'.'),'.',substring(concat(substring-after($qty,'.'),'00'),1,2))" to $qty;

Opération ternaire

Elle permet d'effectuer un choix entre des valeurs d'après une condition et peut être utilisée en tant qu'expression unique à la place d'un bloc if/else. En C/C++, elle se présente sous la forme "cond ? value1 : value2" et en BASIC sous la forme "IFF(cond, value1, value2)". En XPath, la syntaxe est la suivante : "if (cond) then value1 else value2". A noter qu'il ne s'agit pas du bloc d'instruction if de premier niveau dans l'écriture de scripts.

En XPath, il s'agit d'une expression, qui peut être combinée avec d'autres expressions. Dans l'écriture de scripts, elle peut être utilisée comme suit :

move "if (string(D1-UnitOfMeasure/measuresPeakQuantity) = 'D1MP') then 'D1MX' else 'D1SM' " to $func;

Traitement par pipeline

Lors de l'écriture de scripts, il n'est pas facile de créer un morceau de code réutilisable simple parce qu'il n'existe pas de fonctions locales et que l'appel d'un script séparé alourdit le code et nécessite la transmission de paramètres avec ce que cela implique d'opérations supplémentaires. Pour ne pas avoir à copier et coller le même bloc de code dans plusieurs étapes de script similaires, la technique du pipeline est envisageable : elle consiste à décomposer le processus global en grandes étapes distinctes, dont certaines peuvent être partagées par des cheminements alternatifs. Cette technique est couramment employée pour la préparation des paramètres et le formatage des sorties. Un résultat intermédiaire entre des étapes peut être stocké dans une sous-structure "parm".

A la place du code :

if ("type = A")
   prepare params ...
   call services for A ...
   format output ...
end-if;
if ("type = B")
   prepare params ...
   call services for B ...
   format output ...
end-if;

Envisagez l'alternative :

prepare params ...

if ("type = A")
   call services for A ...
end-if;
if ("type = B")
   call services for B ...
end-if;

format output ...

Fonctions XPath 2

La version 2 et plus du moteur de script prend en charge les fonctions et opérateurs XQuery 1.0 ainsi que la norme XQuery 1.0 elle-même avec quelques limitations mineures. Les URL des deux spécifications figurent ci-dessous. Le premier lien pointe sur les fonctions et opérateurs XQuery utilisables.

  • http://www.w3.org/TR/xpath-functions/

  • http://www.w3.org/TR/xquery/

Les fonctions ci-dessous ne peuvent accéder qu'aux systèmes de fichiers locaux. (Pour d'autres protocoles, comme HTTP, elles renvoient une séquence vide.)

  • fn:doc

  • fn:collection