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.
Pour un débatching unitaire, je vous propose une orchestration minimaliste composée de :
// 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'])");
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 +"]" );
Pour un débatching par block, on reprend le pattern de l’orchestration précédente :
// 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'])");
// 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;
// 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 +"]" );
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 :
// 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;
// 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);
<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>
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>
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>
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 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.