[Perl] Utiliser LibXML pour concatener plusieurs fichiers XML

Utiliser LibXML pour concatener plusieurs fichiers XML [Perl] - Perl - Programmation

Marsh Posté le 10-08-2018 à 11:06:10    

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
Reply

Marsh Posté le 10-08-2018 à 11:06:10   

Reply

Marsh Posté le 10-08-2018 à 11:59:42    

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é!  --
Reply

Marsh Posté le 10-08-2018 à 12:04:03    

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

Reply

Marsh Posté le 10-08-2018 à 12:49:12    

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é!  --
Reply

Marsh Posté le 10-08-2018 à 15:07:31    

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é!  --
Reply

Marsh Posté le 10-08-2018 à 15:39:51    

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

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed