Débatching d’un message XML dans une orchestration via XPath

Ugur AGACSEVEN
Publié par Ugur
Catégorie : BizTalk
10/05/2019

Introduction au débatching

Lorsque l’on souhaite débatcher un fichier XML sous Biztalk, il existe deux façons de procéder : soit avec un pipeline, soit avec du XPath.

Ici il va être question de la seconde manière et nous commencerons par le débatching unitaire. Mais pour ce cas, il est plus simple d’utiliser un pipeline car vous n’aurez pas besoin de connaître le langage XPath, il sera plus facile à comprendre et à modifier lors d’un développement ultérieur. Pour plus d’informations à ce sujet, je vous incite donc à aller sur l’article suivant : DEBATCHING D’UN MESSAGE XML DANS UNE ORCHESTRATION AVEC UN PIPELINE.

Cependant lors de débatching plus complexe, l’utilisation du XPath devient plus évident, comme ce que nous allons voir ici, avec le débatching par block (ou paquet) du message, ou encore par filtrage d’un nœud du fichier XML. Pour vous aider à mieux assimiler le concept, un exemple de message comprenant une liste d’animaux étayera mes propos.

 

Orchestrations

Débatching unitaire

Pour un débatching unitaire, je vous propose une orchestration minimaliste composée de :

  • RcvAnimals, la réception du message
  • vCountAnimals, le nombre de message unitaire
// Nombre total de message de type Animal
vNbAnimals = xpath(mReceivedAnimals, "count(/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']/*[local-name()='Animal' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal'])");
  • Loops_AnimalsByNumber, la boucle sur le nombre de message unitaire
  • vCounterAnimal, l’incrémentation du compteur
  • mDebatchedAnimal, la création d’un message unitaire via un XPath qui récupère un seul message de type Animal à la position du compteur
mDebatchedAnimal = xpath(mReceivedAnimals, "/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']/*[local-name()='Animal' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal']["+ vCounterAnimalString +"]" );
  • Send_Animals, qui envoie le message unitaire de type Animal

 

Débatching par block

Pour un débatching par block, on reprend le pattern de l’orchestration précédente :

  • RcvAnimals, la réception du message
  • vCountAnimals, le nombre de message unitaire
// la définition de la taille d’un bloc
vBlockSize = 3;

// Nombre total de message de type Animal
vNbAnimals = xpath(mReceivedAnimals, "count(/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']/*[local-name()='Animal' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal'])");
  • Loops_AnimalsByNumber, la boucle sur le nombre de message unitaire
  • vCounterAnimal, l’incrémentation des compteurs vCounterAnimalMinBlock (position minimum du block) et vCounterAnimalMaxBlock (position maximum du block)
// Incrémentation du compteur max de la taille des blocks
vCounterAnimalMaxBlock = vCounterAnimalMinBlock + vBlockSize;

// Si le nombre total de message est dépassé, alors le compteur max est égal à ce nombre
if (vCounterAnimalMaxBlock > vNbAnimals)
{ vCounterAnimalMaxBlock = vNbAnimals; }

// Conversion des positions min et max en chaîne de caractères pour la requête 
vCounterAnimalMinBlockString = vCounterAnimalMinBlock.ToString();
vCounterAnimalMaxBlockString = vCounterAnimalMaxBlock.ToString();

// Incrémentation du compteur min
vCounterAnimalMinBlock = vCounterAnimalMaxBlock;
  • mDebatchedAnimals, la création d’un message via XPath qui récupère les messages de type Animal entre la position basse vCounterAnimalMinBlockString et de la position haute vCounterAnimalMaxBlockString du block
// Initialisation du message mDebatchedAnimals 
mDebatchedAnimals = mReceivedAnimals;

// XPath récupère des messages sur une intervalle donnée 
xpath(mDebatchedAnimals, "/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']") = xpath(mReceivedAnimals, "/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']/*[local-name()='Animal' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal'][position() > "+ vCounterAnimalMinBlockString +" and position() <= "+ vCounterAnimalMaxBlockString +"]" );
  • Send_Animals, qui envoie un message de type Animals comportant autant de message de type Animal que la taille d’un block ou moins s’il y a des restes à la fin de la dernière boucle

 

Débatching par filtre

Pour un débatching par filtre, le design de l’orchestration se complexifie un peu et on utilise une transaction de type Atomic afin de pouvoir manipuler des noeuds XML dans l’orchestration :

  • RcvAnimals, la réception du message
  • initFlow, l’initialisation du flux
// Choix du nœud à filtrer
vFilter =“Locomotion”; // Ou vFilter = “Diet”;

// Récupération de la liste des différentes locomotions (ou régimes)
vFilterList = xpath(mReceivedAnimals, "/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']/*[local-name()='Animal' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal']/*[local-name()='"+ vFilter +"' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal']");

// Définition du nombre total de locomotions (ou régimes) pour la boucle
vNbFilter = vFilterList.Count;
  • Loops_AnimalsByNumber, la boucle sur le nombre de filtres distinctes
  • vCounterAnimal, l’incrémentation du compteur
  • NewFilter?, la vérification du passage à un nouveau filtre
  • mDebatchedAnimals, la création d’un message via un XPath qui récupère les messages filtrés sur vFilter le nœud et vFilterString la valeur du nœud
// Initialisation du message mDebatchedAnimals 
mDebatchedAnimals = mReceivedAnimals;

// Pour chaque locomotion (=vFilter) distincte, xpath récupère tous les animaux ayant la même valeur (=vFilterString) 
xpath(mDebatchedAnimals, "/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']") = xpath(mReceivedAnimals, "/*[local-name()='Animals' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals']/*[local-name()='Animal' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal'][*[local-name()='"+vFilter+"' and namespace-uri()='http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal']='" + vFilterString + "']" );
// Ajout du nouveau filtre dans une liste (pour la vérification des nouveaux filtres)
vDistinctFilterList.Add(vFilterString);
  • Send_Animals, qui envoie le message comportant la liste des messages filtrés

 

Exemple

Fichier en entrée à débatcher

<ns0:Animals xmlns:ns0="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals">
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Fox</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Terrestrial</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Sloth</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Arboreal</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Mole</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Subterranean</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Horse</ns1:Name>
        <ns1:Diet>Herbivorous</ns1:Diet>
        <ns1:Locomotion>Terrestrial</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Shark</ns1:Name>
        <ns1:Diet>Carnivorous</ns1:Diet>
        <ns1:Locomotion>Aquatic</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Lion</ns1:Name>
        <ns1:Diet>Carnivorous</ns1:Diet>
        <ns1:Locomotion>Terrestrial</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Crow</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Aerial</ns1:Locomotion>
    </ns1:Animal>
</ns0:Animals>

 

Résultat du débatching simple (ou unitaire)

On observe 7 fichiers correspondant aux 7 animaux de notre fichier en entrée :

Et chaque fichier contient un message unitaire de type Animal comme suit :

<ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
  <ns1:Name>Horse</ns1:Name>
  <ns1:Diet>Herbivorous</ns1:Diet>
  <ns1:Locomotion>Terrestrial</ns1:Locomotion>
</ns1:Animal>

 

Résultat du débatching par block

On observe bien 3 fichiers correspondant aux animaux regroupés 3 par 3 de notre fichier en entrée :

Ainsi 2 fichiers contiennent un message de type Animals avec 3 animaux comme suit :

<ns0:Animals
  xmlns:ns0="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals">
  <ns1:Animal
    xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
    <ns1:Name>Fox</ns1:Name>
    <ns1:Diet>Omnivorous</ns1:Diet>
    <ns1:Locomotion>Terrestrial</ns1:Locomotion>
  </ns1:Animal>
  <ns1:Animal
    xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
    <ns1:Name>Sloth</ns1:Name>
    <ns1:Diet>Omnivorous</ns1:Diet>
    <ns1:Locomotion>Arboreal</ns1:Locomotion>
  </ns1:Animal>
  <ns1:Animal
    xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
    <ns1:Name>Mole</ns1:Name>
    <ns1:Diet>Omnivorous</ns1:Diet>
    <ns1:Locomotion>Subterranean</ns1:Locomotion>
  </ns1:Animal>
</ns0:Animals>

Ensuite 1 dernier fichier avec les animaux restants, c’est-à-dire, un seul animal :

<ns0:Animals xmlns:ns0="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals">
  <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
    <ns1:Name>Crow</ns1:Name>
    <ns1:Diet>Omnivorous</ns1:Diet>
    <ns1:Locomotion>Aerial</ns1:Locomotion>
  </ns1:Animal>
</ns0:Animals>

 

Débatching par nœud filtré

Filtre sur le moyen de locomotion des animaux

On observe bien 5 fichiers correspondant aux 5 types de locomotion différentes :

Et chaque fichier contient un message de type Animals regroupant les animaux avec le même moyen de locomotion comme suit :

<ns0:Animals xmlns:ns0="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals">
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Fox</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Terrestrial</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Horse</ns1:Name>
        <ns1:Diet>Herbivorous</ns1:Diet>
        <ns1:Locomotion>Terrestrial</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Lion</ns1:Name>
        <ns1:Diet>Carnivorous</ns1:Diet>
        <ns1:Locomotion>Terrestrial</ns1:Locomotion>
    </ns1:Animal>
</ns0:Animals>

 

Filtre sur le régime alimentaire des animaux

On observe cette fois-ci 3 fichiers correspondant aux 3 types de régimes différents :

Et chaque fichier contient un message de type Animals regroupant les animaux avec le même régime alimentaire comme suit :

<ns0:Animals xmlns:ns0="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animals">
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Fox</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Terrestrial</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Sloth</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Arboreal</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Mole</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Subterranean</ns1:Locomotion>
    </ns1:Animal>
    <ns1:Animal xmlns:ns1="http://MiddleWay.Blogs.Biztalk.XpathDebatching.Animal">
        <ns1:Name>Crow</ns1:Name>
        <ns1:Diet>Omnivorous</ns1:Diet>
        <ns1:Locomotion>Aerial</ns1:Locomotion>
    </ns1:Animal>
</ns0:Animals>

 

Pour aller plus loin…

Pour ne pas avoir à retoucher le code et de tout redéployer à chaque mise à jour de la taille max des blocks ou le nœud à filtrer, je vous conseille d’implémenter ces données via un gestionnaire externe tel que l’application SSO.