Accueil / Blog / Métier / 2015 / Talend Extract XML from XML

Talend tutorial: Extraire un fichier XML contenu dans un autre fichier XML

Par Gaël Pegliasco publié 03/08/2015, édité le 20/02/2016
Talend tutorial: Extraire un fichier XML contenu dans un autre fichier XML

Talend Data Integration

Lors de l'une de mes dernières formations Talend pour Data Integration, il m'a été demandé comment il était possible de traiter les enregistrements d'un fichier XML lui-mếme contenu dans un autre fichier XML ?

Ce cas de figure se présente très souvent quand vous recevez une réponse issue d'une requête HTTP, d'un web service via les protocoles SOAP/REST ou encore dans le cadre de connexion avec des bus de données (ESB).

L'exercice qui semble simple d'un premier abord présente quelques difficultés qui peuvent devenir rapidement bloquantes.

Je vous propose dans ce tutoriel 2 manières de traiter ce problème.

Description du besoin

Nous venons de recevoir un fichier XML contenant lui-même un autre fichier XML dans lequel nous souhaitons extraire des données.
Le fichier source est fourni en téléchargement et se nomme soap.xml
Il s'agit d'une réponse de type SOAP contenant les données de la réponse dans un élément nommé <arg2>.
Le contenu de <arg2> est de type CDATA et contient un fichier xml :

<arg2> 
<![CDATA[
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<exportInscriptionEnLigneType>
<date>2015-04-10</date>
<nbDossiers>2</nbDossiers>
<reference>20150410100</reference>
<listeDossiers>
<dossier>
<numOrdre>1</numOrdre>
<identifiantDossier>AAAAA</identifiantDossier>
</dossier>
<dossier>
<numOrdre>2</numOrdre>
<identifiantDossier>BBBBB</identifiantDossier>
</dossier>
</listeDossiers>
</exportInscriptionEnLigneType>
]]>
</arg2>

Nous souhaitons extraire du fichier contenu dans cet élément <arg2> la liste des dossiers, en affichant pour chaque dossier son numéro et son identifiant :

numidentifiant
1 AAAAA
2 BBBBB

Première solution – tExtractXMLField

La première solution que nous vous proposons utilise 2 composants :

  • Le composant tFileInputXML pour lire le fichier soap.xml et en extraire le champ arg2
  • Le composant tExtractXMLField pour récuper les éléments de type dossier et en extraire le numéro et l'identifiant de chaque dossier

Il se présente comme suit :

 Job, tExtractXMLField

Le composant tFileInputXML permet de lire un fichier XML et d'indiquer une requête XPATH permettant d'en extraire les éléments que l'on souhaite. Puis, pour chaque élément extrait, de ventiler son contenu dans les colonnes du schéma de ce composant. Cette ventilation se fait aussi en utilisant une requête XPATH relative à l'élément courant.

Dans notre cas nous voulons tous les éléments arg2 (il n'y en a qu'un) et ventiler son contenu dans une seule colonne qui contiendra le fichier XML à traiter.

Le paramétrage est alors le suivant :

 Paramétrage tFileInputXML

Le schéma se compose d'une seule colonne de type texte qui contiendra le fichier XML inclus dans la balise arg2 :

tFileInputXML, schéma 

Le composant tExtractXMLField permet quant-à lui, de traiter un champ de type texte issu d'une colonne du flux entrant et d'en extraire des balises au format XML. Il est généralement utilisé pour extraire des informations enregistrées en XML dans les colonnes des tables des bases de données.

La colonne en entrée qu'il analysera sera donc « arg2 » et nous lui demanderons de générer un flux de données pour tous les enregistrements <dossier> contenus dans ce champ.

Son paramétrage est le suivant :

tExtractXMLField, paramétrage

Pour chaque enregistrement extrait il devra afficher son numéro et son identifiant, son schéma est donc le suivant :

tExtractXMLField, schéma

Il ne reste plus qu'à exécuter le job. Mais le résultat n'est pas là.

.---+-----------.
| tLogRow_5 |
|=--+----------=|
|num|identifiant|
|=--+----------=|
'---+-----------'

Le paramétrage des 2 composants semble pourtant bon.

Et il l'est.

Pour bien comprendre ce qui se passe, il est intéressant d'exporter la sortie du composant tFileInputXML dans un fichier texte, fourni avec ce tutorial, et de lire ce fichier texte directement pour le passer au tExtractXMLField.

Nous pourrions lire ce fichier avec un composant tFileInputXML mais cela ne donnerait pas un comportement identique à ce que reçoit le tExtractXMLField. En effet ce composant attend en entrée une colonne de type texte contenant du XML et non du XML déjà parsé.

J'ai donc utilisé le composant tFileInputDelimited pour lire le fichier soap-arg2.txt issu de l'extraction du champ arg2 de la réponse soap.

Lecture fichier soap-arg2.txt

Le paramétrage est très simple : une colonne arg2 de type String et une petite astuce pour le séparateur de lignes : la chaîne « Y_EN_A_PAS » ce qui permet de récupérer tout le contenu du fichier en un seul enregistrement d'une seule colonne. Ce n'est pas très orthodoxe, mais pour dépanner c'est efficace.

Schéma tFileInputDelimited

tExtractXMLField8b.png

En exécutant ce nouveau job, le résultat est le même.

.---+-----------.
| tLogRow_6 |
|=--+----------=|
|num|identifiant|
|=--+----------=|
'---+-----------'

Mais avec en plus un message d'erreur :

Error on line 3 of document : La cible de l'instruction de traitement correspondant à "[xX][mM][lL]" n'est pas autorisée. 
Nested exception: La cible de l'instruction de traitement correspondant à "[xX][mM][lL]" n'est pas autorisée.

Mais quel est le problème ? En fait il y a tout un tas d'espaces au dessus de la balise <?xml version="1.0"> indiquant le type du fichier. Et cela perturbe le bon fonctionnement du composant tExtractXMLField.

Si vous retirez manuellement ces espaces du fichier soap-arg2.txt et relancez le job, tout fonctionne :

.---+-----------.
| tLogRow_6 |
|=--+----------=|
|num|identifiant|
|=--+----------=|
|1 |AAAAA |
|2 |BBBBB |
'---+-----------'

Une solution consiste donc à retirer ces espaces avant de passer le contenu de la balise arg2 au composant tExtractXMLField. Pour cela je vous propose d'utiliser un tJavaRow.

Notre job devient au final :

Lecture fichier soap-arg2.txt

Le contenu du tJavaRow est vraiment basique, il supprime les espaces en début et fin de la colonne arg2 reçue :

output_row.arg2 = input_row.arg2.trim();

Et cette fois tout fonctionne !

Seconde solution : tExtractXMLField + tXMLMap

Les amoureux du tXMLMap seront frustrés par la première solution.
Et ils n'auraient pas forcément tord : il peut s'avérer utile d'utiliser le fichier XML contenu dans arg2 comme un vrai flux XML pour le manipuler dans un tXMLMap.

Cette seconde solution reprend donc le premier job réalisé, avec les 3 composants tFileInputXML, tJavaRow, tExtractXMLField et ajoute un tXMLMap.

tXMLMap1.png

Les 2 premiers composants restent inchangés.

Le troisième composant tExtractXMLField est par contre modifié pour qu'il retourne, non pas des enregistrements sous forme tabulaire, mais un nœud XML de tout le fichier.

Le contenu de la colonne arg2 est retourné tel quel :

  • La requête XPATH de boucle devient « /. » : l'élément racine
  • Une seule colonne, arg2, est retournée, sa requête de sélection est l'élément courant « . » et la case à cocher « obtenir les noeuds » est cochée

tXMLMap2.png

Le schéma a aussi changé, en sortie, arg2 est de type « Document » :

tXMLMap3.png

Le tXMLMap se paramètre quant-à lui « naturellement » :

  • Il convient de recréer la structure du fichier d'entrée
  • De définir l'élément « dossier » comme élément de boucle (loop)
  • De transférer les champs numOrdre et identifiantDossier dans le flux de sortie, avec les bonnes expressions XPATH

 tXMLMap4.png

Et cette fois tout fonctionne bien.

.--------+------------------.
| tLogRow_3 |
|=-------+-----------------=|
|numOrdre|identifiantDossier|
|=-------+-----------------=|
|1 |AAAAA |
|2 |BBBBB |
'--------+------------------'

Pour aller plus loin

 

 

 

ABONNEZ-VOUS À LA NEWSLETTER !
Voir aussi
Makina Corpus devient partenaire Gold de Talend Makina Corpus devient partenaire Gold de Talend 12/05/2009

Talend Tutoriel : comprendre les connexions iterate 20/12/2013

Le lien iterate est décrit assez succinctement dans le manuel utilisateur de Talend (User Guide). ...

Geocoder avec Talend Open Studio 22/05/2014

Mettre en place un job de geocodage d'adresses (depuis un fichier XLS) dans l'ETL Talend Open ...

Créer une carte avec Umap Créer une carte avec Umap 03/07/2019

[ Tuto ] créer une carte utilisant OpenStreetMap et y ajouter ou importer des données, puis ...

Python tutorial : Understanding Python threading 05/05/2014

As many others languages, Python provides a great and simple library to use threads. This library ...