Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2330 connectés 

  FORUM HardWare.fr
  Programmation
  Perl

  [Perl] Utiliser LibXML pour concatener plusieurs fichiers XML

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Perl] Utiliser LibXML pour concatener plusieurs fichiers XML

n°2318921
Sethenssen
Posté le 10-08-2018 à 11:06:10  profilanswer
 

Bonjour,
 
J'ai un dossier contenant x fichiers XML.
Le but et de concaterner les x fichiers pour ne créer qu'un seul gros fichier XML.
 
On va dire qu'avec le code ci-dessous j'arrive à concatener mais je n'arrive pas à faire deux choses:
1. ajouter un retour à la ligne après la fermeture de chaque balise.
2. je voudrai rassembler tous les tags ensemble alors que là j'affiche pour chaque XML d'abord son Product, ensuite Series, Episode et VodItem
 
J'ai donc ajouté 2 exemples et le fichier de sortie désiré pour plus de clarté.
Ça sera plus simple à comprendre je pense qu'un long discours.
 
Merci d'avance pour vos lumières sur cette demande.
 
Voici le code

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings 'all';
  4. use POSIX;
  5. use XML::LibXML;
  6.  
  7. print strftime('%Y-%m-%d %H:%M:%S', localtime), "\n";
  8. my $date =  strftime('%Y-%m-%dT%H:%M:%SZ', localtime);
  9.  
  10. my $DIR = "/folder/";
  11.  
  12. opendir(DIR, $DIR);
  13. my @SEARCH = grep(/^exemple.*.xml$/, readdir(DIR));
  14. closedir(DIR);
  15.  
  16. if (scalar(@SEARCH)) {
  17.        my $new_doc = XML::LibXML::Document->new('1.0','utf-8');
  18.        my $new_root = $new_doc->createElement('ScheduleProvider');
  19.        $new_root->setAttribute('id','PPP');
  20.        $new_root->setAttribute('scheduleDate',"$date" );
  21.  
  22.        for my $fn (@SEARCH) {
  23.                my $filename = $DIR . $fn;
  24.                my $doc = XML::LibXML->load_xml(location => $filename);
  25.                my $dom = $doc->getDocumentElement;
  26.  
  27.                # on attache les nodes ensemble
  28.                for my $xpath (qw<//Product //Series //Episode //VodItem> ) {
  29.                $new_root->appendChild($_) for $dom->findnodes($xpath);
  30.                }
  31.        }
  32.  
  33.        $new_doc->setDocumentElement($new_root);
  34.  
  35.        print $new_doc->toString;
  36. }


 
Voici le stdout du code:

Code :
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <ScheduleProvider id="PPP" scheduleDate="2018-08-09T09:53:31Z"><Product>
  3.       <node>id="P147897"</node>
  4.     </Product><Series>
  5.       <node>id="S147897"</node>
  6.     </Series><Episode>
  7.       <node>id="E147897"</node>
  8.     </Episode><VodItem>
  9.       <node>id="V147897"</node>
  10.     </VodItem><Product>
  11.       <node>id="P434324239"</node>
  12.     </Product><Series>
  13.       <node>id="S434324239"</node>
  14.     </Series><Episode>
  15.       <node>id="E434324239"</node>
  16.     </Episode><VodItem>
  17.       <node>id="V434324239"</node>
  18.     </VodItem></ScheduleProvider>


 
exemple1.xml

Code :
  1. <?xml version="1.0" encoding="utf-8" standalone="yes"?>
  2. <ScheduleProvider id="PPP" scheduleDate="2018-08-09T09:53:31Z">
  3.    <Product>
  4.      <node>id="P434324239"</node>
  5.    </Product>
  6.    <Series>
  7.      <node>id="S434324239"</node>
  8.    </Series>
  9.    <Episode>
  10.      <node>id="E434324239"</node>
  11.    </Episode>
  12.    <VodItem>
  13.      <node>id="V434324239"</node>
  14.    </VodItem>
  15. </ScheduleProvider>


 
exemple2.xml

Code :
  1. <?xml version="1.0" encoding="utf-8" standalone="yes"?>
  2. <ScheduleProvider id="PPP" scheduleDate="2018-08-09T19:53:31Z">
  3.    <Product>
  4.      <node>id="P147897"</node>
  5.    </Product>
  6.    <Series>
  7.      <node>id="S147897"</node>
  8.    </Series>
  9.    <Episode>
  10.      <node>id="E147897"</node>
  11.    </Episode>
  12.    <VodItem>
  13.      <node>id="V147897"</node>
  14.    </VodItem>
  15. </ScheduleProvider>


 
Résultat attendu:

Code :
  1. <?xml version="1.0" encoding="utf-8" standalone="yes"?>
  2. <ScheduleProvider id="PPP" scheduleDate="2018-08-09T09:53:31Z">
  3.     <Product>
  4.       <node>id="P434324239"</node>
  5.     </Product>
  6.     <Product>
  7.       <node>id="P147897"</node>
  8.     </Product>
  9.     <Series>
  10.       <node>id="S434324239"</node>
  11.     </Series>
  12.     <Series>
  13.       <node>id="S147897"</node>
  14.     </Series>
  15.     <Episode>
  16.       <node>id="E434324239"</node>
  17.     </Episode>
  18.     <Episode>
  19.       <node>id="E147897"</node>
  20.     </Episode>
  21.     <VodItem>
  22.       <node>id="V434324239"</node>
  23.     </VodItem>
  24.     <VodItem>
  25.       <node>id="V147897"</node>
  26.     </VodItem>
  27. </ScheduleProvider>


Message édité par Sethenssen le 10-08-2018 à 11:06:30
mood
Publicité
Posté le 10-08-2018 à 11:06:10  profilanswer
 

n°2318929
gilou
Modérateur
Modzilla
Posté le 10-08-2018 à 11:59:42  profilanswer
 

Bonjour,
Je réponds sur le premier point:
Il faut indiquer a toString qu'on veut un formattage un peu moins brut de décoffrage. Ceci devrait faire l'affaire:
print $new_doc->toString(1);
 
Sur ton premier exemple (stdout du code), voici ce qu'on a sans paramètre (équivalent a la valeur 0) avec un script minimaliste (load_xml suivi de print du document) :

Code :
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <ScheduleProvider id="PPP" scheduleDate="2018-08-09T09:53:31Z"><Product>
  3.      <node>id="P147897"</node>
  4.    </Product><Series>
  5.      <node>id="S147897"</node>
  6.    </Series><Episode>
  7.      <node>id="E147897"</node>
  8.    </Episode><VodItem>
  9.      <node>id="V147897"</node>
  10.    </VodItem><Product>
  11.      <node>id="P434324239"</node>
  12.    </Product><Series>
  13.      <node>id="S434324239"</node>
  14.    </Series><Episode>
  15.      <node>id="E434324239"</node>
  16.    </Episode><VodItem>
  17.      <node>id="V434324239"</node>
  18.    </VodItem></ScheduleProvider>


et le même avec le paramètre a 1:

Code :
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <ScheduleProvider id="PPP" scheduleDate="2018-08-09T09:53:31Z">
  3.  <Product>
  4.      <node>id="P147897"</node>
  5.    </Product>
  6.  <Series>
  7.      <node>id="S147897"</node>
  8.    </Series>
  9.  <Episode>
  10.      <node>id="E147897"</node>
  11.    </Episode>
  12.  <VodItem>
  13.      <node>id="V147897"</node>
  14.    </VodItem>
  15.  <Product>
  16.      <node>id="P434324239"</node>
  17.    </Product>
  18.  <Series>
  19.      <node>id="S434324239"</node>
  20.    </Series>
  21.  <Episode>
  22.      <node>id="E434324239"</node>
  23.    </Episode>
  24.  <VodItem>
  25.      <node>id="V434324239"</node>
  26.    </VodItem>
  27. </ScheduleProvider>


A+,


Message édité par gilou le 10-08-2018 à 12:00:35

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2318931
Sethenssen
Posté le 10-08-2018 à 12:04:03  profilanswer
 

Ah pas mal merci ! Je ne savais pas qu'on pouvait jouer sur cette valeur.

n°2318936
gilou
Modérateur
Modzilla
Posté le 10-08-2018 à 12:49:12  profilanswer
 

En fait non, bizarrement, ça marche sur le fichier output mais pas sur tes exemples et j'ai pas l'intention de chercher pourquoi.
On va donc faire plus sophistiqué:
Tu mets  
use XML::LibXML::PrettyPrint;::PrettyPrint;
après ton use XML::LibXML::PrettyPrint;
 
tu définis cette variable
my $pp = XML::LibXML::PrettyPrint->new(
    element => {
        inline   => ['node'],
    },
    indent_string => "  ",
    );
(par défaut tout sera indenté, sauf l'élément node, et l'indentation sera de deux caractères)
et tu ajoutes la ligne  
$pp->pretty_print($new_doc);
juste avant celle avec  
print $new_doc->toString;
 
Et ça ça marche.

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings 'all';
  4. use POSIX;
  5. use XML::LibXML;
  6. use XML::LibXML::PrettyPrint;
  7.  
  8. print strftime('%Y-%m-%d %H:%M:%S', localtime), "\n";
  9. my $date =  strftime('%Y-%m-%dT%H:%M:%SZ', localtime);
  10.  
  11. my $DIR = "/folder/";
  12.  
  13. opendir(DIR, $DIR);
  14. my @SEARCH = grep(/^exemple.*.xml$/, readdir(DIR));
  15. closedir(DIR);
  16.  
  17. if (scalar(@SEARCH)) {
  18.        my $new_doc = XML::LibXML::Document->new('1.0','utf-8');
  19.        my $new_root = $new_doc->createElement('ScheduleProvider');
  20.        $new_root->setAttribute('id','PPP');
  21.        $new_root->setAttribute('scheduleDate',"$date" );
  22.        my $pp = XML::LibXML::PrettyPrint->new(
  23.                element => { inline => ['node'], },
  24.                indent_string => "  ",
  25.                );
  26.  
  27.        for my $fn (@SEARCH) {
  28.                my $filename = $DIR . $fn;
  29.                my $doc = XML::LibXML->load_xml(location => $filename);
  30.                my $dom = $doc->getDocumentElement;
  31.  
  32.                # on attache les nodes ensemble
  33.                for my $xpath (qw<//Product //Series //Episode //VodItem> ) {
  34.                $new_root->appendChild($_) for $dom->findnodes($xpath);
  35.                }
  36.        }
  37.  
  38.        $new_doc->setDocumentElement($new_root);
  39.  
  40.        $pp->pretty_print($new_doc);
  41.        print $new_doc->toString;
  42. }


 
donne en sortie

Code :
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <ScheduleProvider id="PPP" scheduleDate="2018-08-10T12:56:23Z">
  3.  <Product>
  4.    <node>id="P434324239"</node>
  5.  </Product>
  6.  <Series>
  7.    <node>id="S434324239"</node>
  8.  </Series>
  9.  <Episode>
  10.    <node>id="E434324239"</node>
  11.  </Episode>
  12.  <VodItem>
  13.    <node>id="V434324239"</node>
  14.  </VodItem>
  15.  <Product>
  16.    <node>id="P147897"</node>
  17.  </Product>
  18.  <Series>
  19.    <node>id="S147897"</node>
  20.  </Series>
  21.  <Episode>
  22.    <node>id="E147897"</node>
  23.  </Episode>
  24.  <VodItem>
  25.    <node>id="V147897"</node>
  26.  </VodItem>
  27. </ScheduleProvider>


 
A+,


Message édité par gilou le 10-08-2018 à 12:58:33

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2318938
gilou
Modérateur
Modzilla
Posté le 10-08-2018 à 15:07:31  profilanswer
 

Bon, pour une version qui fait tout ce que tu demandais:
 

Code :
  1. #!/usr/local/bin/perl
  2. use strict;
  3. use warnings 'all';
  4. use POSIX;
  5. use XML::LibXML;
  6. use XML::LibXML::PrettyPrint;
  7.  
  8. my $date =  strftime('%Y-%m-%dT%H:%M:%SZ', localtime);
  9.  
  10. my $DIR = "/folder/";
  11.  
  12. opendir(DIR, $DIR);
  13. my @SEARCH = grep(/^exemple.*.xml$/, readdir(DIR));
  14. closedir(DIR);
  15.  
  16. if (scalar(@SEARCH)) {
  17.    my $new_doc = XML::LibXML::Document->new('1.0','utf-8');
  18.    my $new_root = $new_doc->createElement('ScheduleProvider');
  19.    $new_root->setAttribute('id','PPP');
  20.    $new_root->setAttribute('scheduleDate',"$date" );
  21.    $new_doc->setDocumentElement($new_root);
  22.  
  23.    # Je cree un hash ou collecter les noeuds a insérer dans le document résultat
  24.    # les clés sont les types des noeuds à insérer
  25.    my @nodes = qw(Product Series Episode VodItem);
  26.    my %nodelists;
  27.    $nodelists{$_} = [] foreach (@nodes);
  28.    
  29.    for my $fn (@SEARCH) {
  30.        my $filename = $DIR . $fn;
  31.        my $doc = XML::LibXML->load_xml(location => $filename);
  32.        my $dom = $doc->getDocumentElement;
  33.        foreach (@nodes) {
  34.            foreach my $node ($dom->findnodes('//' . $_)) {
  35.                # je detache le noeud et l'attache a son futur document
  36.                # et je l'ajoute a la liste des noeuds de son type a insérer
  37.                $node->unbindNode();
  38.                $node->setOwnerDocument($new_doc);
  39.                push @{$nodelists{$_}}, $node;
  40.            }
  41.        }
  42.    }
  43.  
  44.    # J'ajoute en bloc tous les noeuds a insérer, type par type
  45.    foreach (@nodes) {
  46.        foreach (@{$nodelists{$_}}) {
  47.            $new_root->appendChild($_);
  48.        }
  49.    }
  50.    
  51.    my $pp = XML::LibXML::PrettyPrint->new(
  52.        element => { inline => ['node'], },
  53.        indent_string => "  ",
  54.        );
  55.    $pp->pretty_print($new_doc);
  56.    print $new_doc->toString;
  57. }


a mes indentations près, bouffés par le forum, grand dévoreur de tabs.
 
A+,


Message édité par gilou le 10-08-2018 à 15:26:31

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2318939
Sethenssen
Posté le 10-08-2018 à 15:39:51  profilanswer
 

C'est parfait Gilou ! Encore merci
Je ne sais pas comment tu as l'idée d'utiliser PrettyPrint mais c'est pas mal


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Perl

  [Perl] Utiliser LibXML pour concatener plusieurs fichiers XML

 

Sujets relatifs
[Perl] Optimisation code perl CGI - Problème de performanceutiliser les valeurs d'un fichier texte [ résolu ].
[Perl] Détecter un champ en UTF-8[Perl] Module JSON / Lire un fichier
Delphi / TurboPascal : Detecter si un application est utiliser (focus)[Perl] Remplacer plusieurs lignes par le résultat d'un appel externe
[PERL] remplacer un mot dans un fichierutiliser la console avec javascript
[Perl] Comparaison de fichiersraytracer : utiliser opengl ?
Plus de sujets relatifs à : [Perl] Utiliser LibXML pour concatener plusieurs fichiers XML


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR