Précédent   Forum du club des développeurs et IT Pro > Autres langages > Perl > Modules
Modules Toutes vos questions sur l'utilisation, l'installation, la création de modules Perl sous Windows/Linux/Unix/MacOS. Avant de poster, veuillez consulter les FAQs perl, les cours Perl et les sources Perl.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 20/08/2012, 17h53   #1
flash21
Invité régulier
 
Homme
Inscription : octobre 2010
Messages : 45
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : octobre 2010
Messages : 45
Points : 6
Points : 6
Par défaut Traitement d'un fichier xml volumineux de presque 100Mo

Bonjour,

je reviens vers vous à propos d'un problème que j'avais eu il y a quelques jours à propos de l'ajout ou de la suppression d'attributs dans un fichier xml. J'ai vu avec les tutos de Djibril qu'on pouvait uniquement charger en mémoire la ligne qu'on souhaitait. Après avoir parcouru plein de documentations et notamment le CPAN, je ne comprends pas comment cela est possible. Serait-il possible de me montrer comment avec l'exemple de fichier cité, je peux charger uniquement la ligne ENVELOPPE (l'entête). Le reste des lignes chargées ne me sert pas en réalité. Merci d'avance pour votre retour.

Citation:
Envoyé par flash21 Voir le message
Bonjour,

je cherche désespérément à modifier ou supprimer des attributs d'un fichier xml mais je n'y arrive pas. Ce qu'il me faudrait en fait, c'est à la lecture fichier aller modifier (ou supprimer) certains attributs d'une balise afin d'écrire le fichier résultat. J'arrive à écrire mon fichier en sortie mais les attributs ne sont pas modifiés. Pouvez-vous m'aider svp?
Ci-dessous mon code :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
#!/usr/bin/perl
 
use Carp;
use warnings;
use XML::Twig;
#use XML::LibXML;
use File::Temp qw(tempfile tempdir);
use Getopt::Long;
 
my ($repertoire, $fichier) = ();
GetOptions( 'fichier|i=s' => \$fichier, 'repertoire|d=s' => \$repertoire);
 
if(not defined $fichier or not defined $repertoire) {
  die "Fichier source ou répertoire de travail manquant!";
}
creation fichier resultat avec non unique
my($fh, $filename) = tempfile( "FILEOUT"."_". 'XXXXXXXX', SUFFIX => '.xml', DIR => $repertoire );
binmode $fh, ':encoding(UTF-8)';#UTF8 format
 
# Lecture
my $twig = XML::Twig->new( pretty_print => 'indented' );
$twig->parsefile($fichier);
my $twig_SHIPMENT_EXPECTED_INFORMATION = $twig->root->first_child('ENVELOPPE');
removeAttribute($twig_ENVELOPPE, "xmlns="http://www.secondsiteweb.com/WMSXMLMessages"");
=head1
Je n'arrive pas à supprimer ou modifier un attribut en particulier dans mon fichier xml
quelqu'un pourrait il m'aider?
exemple de fichier xml :
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ENVELOPPE xmlns:premier="http://www.siteweb/XMLDataTypes" xmlns="http://www.secondsiteweb.com/WMSXMLMessages" xmlns:troisieme="http://www.troisiemesiteweb.com/GateDataTypes" xmlns:quatrieme="http://www.w3.org/2001/XMLSchema-instance">
	<SequenceId>1</SequenceId>
	<DateDuJour>25</DateDuJour>
</ENVELOPPE>
 
J'aimerai avoir un fichier comme suit : 
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ENVELOPPE xmlns:premier="http://www.siteweb/XMLDataTypes" xmlns:ajout="http://www.secondsiteweb.com/WMSXMLMessages" xmlns:troisieme="http://www.troisiemesiteweb.com/GateDataTypes" xmlns:quatrieme="http://www.w3.org/2001/XMLSchema-instance">
	<SequenceId>1</SequenceId>
	<DateDuJour>25</DateDuJour>
</ENVELOPPE>
 
ou supprimer tout simplement le :  xmlns="http://www.secondsiteweb.com/WMSXMLMessages"
 
=cut
$twig->print($fh);
close $fh;
flash21 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 20/08/2012, 17h59   #2
djibril
Responsable Perl et Outils

 
Avatar de djibril
 
Homme
Inscription : avril 2004
Messages : 13 481
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 33
Localisation : France

Informations forums :
Inscription : avril 2004
Messages : 13 481
Points : 31 590
Points : 31 590
La première des choses est de nous montrer votre programme actuel.
Sinon, pour analyser le XML par bout, il faut utiliser les twig_handler.
__________________
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
djibril est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 09h02   #3
flash21
Invité régulier
 
Homme
Inscription : octobre 2010
Messages : 45
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : octobre 2010
Messages : 45
Points : 6
Points : 6
Oui c'est vrai, j'avais oublié de montrer mon code. Le voici :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/perl
 
use Carp;
#use warnings;
use XML::Twig;
use File::Temp qw(tempfile tempdir);
use Getopt::Long;
 
my ($repertoire, $fichier,$temporaire) = ();
GetOptions( 'fichier|i=s' => \$fichier,'nomtemporaire|t=s' => \$temporaire, 'repertoire|r=s' => \$repertoire);
 
my $Nom = "ballon";
my $CodeLieu = "stadium"; 
 
if(not defined $fichier or not defined $repertoire) {
  die "Fichier source ou répertoire de travail manquant!";
}
 
# Lecture du fichier XML
my $twig = XML::Twig->new(
  pretty_print  => 'indented',
  Twig_handlers => { 'ENVELOPPE' => \&ENVELOPPE },
);
$twig->parsefile($fichier);
 
sub ENVELOPPE
{
	my ($twig, $twig_ENVELOPPE) = @_;
	# Création d'un fichier avec un nom unique
	my($fh, $filename) = tempfile( $temporaire.'XXXX', SUFFIX => '_ENVELOPPE', DIR => $repertoire );
	binmode $fh, ':encoding(UTF-8)';
	# Lecture du fichier XML
	my $twig = XML::Twig->new( pretty_print => 'indented' );
	$twig->parsefile($fichier);
	# Suppression de l'attribut xmlns
	$twig_ENVELOPPE->del_att('xmlns');
	$twig_ENVELOPPE = $twig->root;
	$twig_ENVELOPPE->insert_new_elt(ENTETE => {Nom => $Nom, CodeLieu => $CodeLieu});	
	$twig->print($fh);
	$twig->purge;
	close $fh;
}
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ENVELOPPE xmlns:premier="http://www.siteweb/XMLDataTypes" xmlns="http://www.secondsiteweb.com/WMSXMLMessages" xmlns:troisieme="http://www.troisiemesiteweb.com/GateDataTypes" xmlns:quatrieme="http://www.w3.org/2001/XMLSchema-instance">
	<SequenceId>1</SequenceId>
	<DateDuJour>25</DateDuJour>
	<SequenceDebut>1</SequenceDebut>
	<DateDuJour>25</DateDuJour>
	<SequenceId>1</SequenceId>
	<Mois>25</Mois>
	<Annee>1</Annee>
	<DateDuJour>25</DateDuJour>
	<SequenceId>1</SequenceId>
	<DateDuJour>25</DateDuJour>
	<SequenceId>1</SequenceId>
	<DateDuJour>25</DateDuJour>
	<SequenceId>1</SequenceId>
	<DateDuJour>25</DateDuJour>
</ENVELOPPE>
Le fichier ci dessus est juste un exemple. Le vrai fait plus de 2000000 de lignes. J'ai compris que le twig_handle permettait de charger uniquement la balise dont on a besoin. Je me demande comment ça pourrait marcher ici étant donné que Enveloppe inclu tout l'xml. Charger cette balise implique de charger le fichier en entier.

Pour executer le script : perl script.pl -i fichier.xml -t fichier.xml -r .

Merci pour votre aide
flash21 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 11h32   #4
djibril
Responsable Perl et Outils

 
Avatar de djibril
 
Homme
Inscription : avril 2004
Messages : 13 481
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 33
Localisation : France

Informations forums :
Inscription : avril 2004
Messages : 13 481
Points : 31 590
Points : 31 590
Bonjour,

Le code est un peu bizarre car dans la procédure enveloppe, vous créez un fichier en lisant une deuxième fois le fichier XML.

Ce code devrait déjà être mieux :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/perl
 
use Carp;
#use warnings;
use XML::Twig;
use File::Temp qw(tempfile tempdir);
use Getopt::Long;
 
my ($repertoire, $fichier,$temporaire) = ();
GetOptions( 'fichier|i=s' => \$fichier,'nomtemporaire|t=s' => \$temporaire, 'repertoire|r=s' => \$repertoire);
 
my $Nom = "ballon";
my $CodeLieu = "stadium"; 
 
if(not defined $fichier or not defined $repertoire) {
  die "Fichier source ou répertoire de travail manquant!";
}
 
# Lecture du fichier XML
my $twig = XML::Twig->new(
  pretty_print  => 'indented',
  Twig_handlers => { 'ENVELOPPE' => \&ENVELOPPE },
);
 
# Création d'un fichier avec un nom unique
my($fh, $filename) = tempfile( $temporaire.'XXXX', SUFFIX => '_ENVELOPPE', DIR => $repertoire );
binmode $fh, ':encoding(UTF-8)';
 
$twig->parsefile($fichier);
 
close $fh;
 
sub ENVELOPPE
{
	my ($twig, $twig_ENVELOPPE) = @_;
	# Suppression de l'attribut xmlns
	$twig_ENVELOPPE->del_att('xmlns');
	$twig_ENVELOPPE = $twig->root;
	$twig_ENVELOPPE->insert_new_elt(ENTETE => {Nom => $Nom, CodeLieu => $CodeLieu});	
	$twig->print($fh);
	$twig->purge;
}
__________________
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
djibril est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 12h46   #5
flash21
Invité régulier
 
Homme
Inscription : octobre 2010
Messages : 45
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : octobre 2010
Messages : 45
Points : 6
Points : 6
Oui c'est vrai. C'était une erreur de ma part. Merci de l'avoir corrigé. Mon problème reste entier cependant. Je charge tout le bloc en mémoire alors que j'aimerais ne charger que la première ligne. Le Twig_handlers ne m'est pas bien utile dans ce cas.
flash21 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 13h26   #6
djibril
Responsable Perl et Outils

 
Avatar de djibril
 
Homme
Inscription : avril 2004
Messages : 13 481
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 33
Localisation : France

Informations forums :
Inscription : avril 2004
Messages : 13 481
Points : 31 590
Points : 31 590
Étant donné que tu souhaites modifier (et non juste extraire) des données précises, il sera impossible pour XML::Twig de faire autrement. De plus, tu insères de nouvelles données donc bon.
As-tu eu des soucis de parsing pour tes gros fichiers ? As-tu fait des tests car 180Mo, c'est rien !
__________________
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
djibril est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 13h29   #7
djibril
Responsable Perl et Outils

 
Avatar de djibril
 
Homme
Inscription : avril 2004
Messages : 13 481
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 33
Localisation : France

Informations forums :
Inscription : avril 2004
Messages : 13 481
Points : 31 590
Points : 31 590
Maintenant, si tu es sûr de la forme de tous tes XML et si le principe revient uniquement qu'à changer l'attribut de la balise enveloppe, exceptionnellement, tu pourras utiliser des regex à la place du module, mais ton programme sera instable si tes XML changent de forme.
__________________
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
djibril est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 15h24   #8
flash21
Invité régulier
 
Homme
Inscription : octobre 2010
Messages : 45
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : octobre 2010
Messages : 45
Points : 6
Points : 6
Pour parser des fichiers de 180 Mo disons en local, je n'ai pas de soucis. Seulement sur le serveur distant dans lequel est censé s'exécuter le script, j'ai une erreur tout le temps qui dit que le temps de traitement du fichier a dépassé 1mn.
flash21 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 15h27   #9
flash21
Invité régulier
 
Homme
Inscription : octobre 2010
Messages : 45
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : octobre 2010
Messages : 45
Points : 6
Points : 6
Y a t'il un moyen de ne charger le fichier ligne par ligne. Est-ce que le module xml SAX par exemple me permettrait charger le fichier ligne par ligne? Un peu comme un if else. Si c'est la première ligne, je récupère la ligne, je fais mes modifications, sinon je ne charge pas la ligne, je la réécris telle quelle.
flash21 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 15h34   #10
djibril
Responsable Perl et Outils

 
Avatar de djibril
 
Homme
Inscription : avril 2004
Messages : 13 481
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 33
Localisation : France

Informations forums :
Inscription : avril 2004
Messages : 13 481
Points : 31 590
Points : 31 590
Citation:
Envoyé par flash21 Voir le message
Pour parser des fichiers de 180 Mo disons en local, je n'ai pas de soucis. Seulement sur le serveur distant dans lequel est censé s'exécuter le script, j'ai une erreur tout le temps qui dit que le temps de traitement du fichier a dépassé 1mn.
Comment ça ? Cela n'a rien avoir avec Perl là ! Faudrait nous en dire un peu plus !
__________________
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
djibril est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/08/2012, 15h53   #11
djibril
Responsable Perl et Outils

 
Avatar de djibril
 
Homme
Inscription : avril 2004
Messages : 13 481
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 33
Localisation : France

Informations forums :
Inscription : avril 2004
Messages : 13 481
Points : 31 590
Points : 31 590
Citation:
Envoyé par flash21 Voir le message
Y a t'il un moyen de ne charger le fichier ligne par ligne. Est-ce que le module xml SAX par exemple me permettrait charger le fichier ligne par ligne? Un peu comme un if else. Si c'est la première ligne, je récupère la ligne, je fais mes modifications, sinon je ne charge pas la ligne, je la réécris telle quelle.
Comme je te l'ai déjà dit, tu ne peux pas faire de ligne à ligne via un parser de fichier structuré, ce qui est tout à fait normal.
La seule façon de faire du ligne à ligne = lire le fichier à la perl et faire des regex. C'est déjà ce que je t'ai suggéré plus haut en dernier ressort.
__________________
Pas de questions technique par messagerie privée (lisez les règles du forum Perl) et pour les nouveaux !
djibril est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 08h37.


 
 
 
 
Partenaires

Hébergement Web