1. <<DOC;
  2. Uyên-To DOAN-RABIER
  3. Ruixin HE
  4. Mohamed Sofiane KERROUA
  5.  
  6. BàO 2 - Xml::Rss
  7.  
  8. En utilisant des expressions régulières et le module Xml::Rss, produit en sortie des fichiers contenant les résumés de fils rss
  9. contenus dans des fichiers xml dans une arborescence donnée. Produit en plus des fichiers étiquetés par tree-tagger et
  10. des fichiers exploitables par Cordial (>2Mo et en iso-8859-1).
  11.  
  12. usage : bao2_xmlrss.pl nom_du_répertoire
  13.  
  14. DOC
  15.  
  16. #/usr/bin/perl
  17. #use strict;
  18. #use warnings;
  19. use Unicode::String qw(utf8);
  20. use XML::RSS;
  21.  
  22. #-----------------------------------------------------------
  23. # Procédure principale
  24. #-----------------------------------------------------------
  25. #Les fichiers sont créés dans un répertoire "resultat"
  26. mkdir(resultat);
  27. #Les fichiers pour cordial sont créés dans un répertoire "cordial"
  28. mkdir(cordial);
  29. mkdir("./cordial/fichiers");
  30.  
  31. #-----------------------------------------------------------
  32. # on initialise une variable $rep contenant le flux de sortie
  33. my $rep="$ARGV[0]";
  34. # on s'assure que le nom du répertoire ne se termine pas par un "/"
  35. $rep=~ s/[\/]$//;
  36.  
  37. #-----------------------------------------------------------
  38. # Initialisation d'un tableau de hash évitant la répétition du contenu des fils rss
  39. my %tabcontenu = ();
  40. &parcoursarborescencefichiers($rep);    #recurse!
  41.  
  42. #-----------------------------------------------------------
  43. $cheminrep ="./resultat";
  44. # On ouvre le répertoire "résultat" contenant les fichiers de sortie xml et txt
  45. # On ajoute à chaque fichier xml la balise fermante </file>
  46. # On convertit chaque fichier txt en iso-8859-1 et on le place dans le dossier cordial
  47. opendir(DIRS,$cheminrep) or die "can't open $cheminrep: $!\n";
  48. my @files = readdir(DIRS);
  49. closedir(DIRS);
  50. foreach my $fichier(@files){
  51.     next if $fichier =~ /^\.\.?$/;
  52.             # A chaque fichier xml crée en sortie on ajoute la balise fermante </file>
  53.             if($fichier =~/\.xml$/){
  54.                 open(OUT,">>:encoding(utf-8)","./resultat/$fichier");
  55.                 print OUT "</file>\n";
  56.                 close(OUT);
  57.             }
  58.             # Chaque fichier txt est converti en iso-8859-1 pour un traitement avec Cordial
  59.         if($fichier=~/\.txt$/){
  60.     open(IN,"<:encoding(utf8)","./resultat/$fichier");
  61.     open (OUT4, ">:encoding(iso-8859-1)","./cordial/iso_$fichier");
  62.     while(<IN>){
  63.          print OUT4 $_;
  64.     }
  65.         close (OUT4);
  66.         close (IN);
  67.     }
  68. }
  69.  
  70. #-----------------------------------------------------------
  71. # Ouverture du répertoire cordial afin de découper les fichiers de plus de 2Mo pour les traiter avec Cordial
  72. $cordial="./cordial";
  73. opendir(COR, $cordial) or die "can't open $path: $!\n";
  74. my @fics = readdir(COR);
  75. closedir(COR);
  76. foreach my $fich(@fics){
  77.     next if $fich =~ /^\.\.?$/;
  78.     &decoupe($fich); # Procédure qui permet de couper un fichier de plus de 2Mo en plusieurs fichiers de 2Mo maximum
  79. }
  80.  
  81. exit; # Fin du programme
  82.  
  83. #-----------------------------------------------------------
  84. # Procédure "parcoursarborescencefichiers"
  85. # Parcours une arborescence et traite chaque fichier xml contenant des fils rss
  86. # Donnée : un répértoire passé en paramètre par valeur
  87. # Résultats : - le résultat du traitement au format txt
  88. #             - le résultat du traitement au format xml
  89. #             - le résultat du traitement au format xml avec un étiquetage réalisé tree-tagger
  90. sub parcoursarborescencefichiers {
  91. #-----------------------------------------------------------
  92. # Récupération du répertoire et ouverture du répertoire
  93.     my $path = shift(@_);
  94.     opendir(DIR, $path) or die "can't open $path: $!\n";
  95.     my @files = readdir(DIR);
  96.     closedir(DIR);
  97.  
  98. #-----------------------------------------------------------
  99. # Traitement de chaques fichiers contenu dans le répertoire
  100.     foreach my $file (@files) {
  101.         next if $file =~ /^\.\.?$/;
  102.         $file = $path."/".$file;
  103. # Si on tombe sur un répertoire on relance la procédure
  104.         if (-d $file) {
  105.             &parcoursarborescencefichiers($file);   #recurse!
  106.         }
  107.        
  108. #-----------------------------------------------------------       
  109. # Traitement du fichier
  110.         if (-f $file) {
  111. # Si le fichier est un fichier xml et si ce fichier xml n'est pas un fichier ne contenant pas fils rss on le traite
  112.             if(($file=~/\.xml$/) && ($file!~/\/fil.+\.xml$/) && ($file !~/0,2-3404,1-0,0\.xml$/)){
  113.            
  114. # Initialisation des différentes variables
  115.             my $encodage = "";
  116.             my $encodagesortie="utf-8";
  117.             my $texte="";
  118.  
  119. #-----------------------------------------------------------
  120. # Si le fichier est vide pas de traitement         
  121.             if(-z $file){
  122.                 print "$file est vide pas de traitement\n";
  123.             }else{
  124.            
  125. #-----------------------------------------------------------
  126. # Détection de l'encodage du fichier
  127.                 open(FIC,$file);
  128.                 while (my $ligne=<FIC>) {
  129.                     $ligne =~ s/\n//g;
  130.                     if($ligne =~/(iso-8859-1|utf-8)/ig){
  131.                         $encodage = $1;
  132.                     }
  133.                 }
  134.                 close(FIC);
  135.                
  136. #-----------------------------------------------------------
  137. # Initialisation de la méthode du module xml::rss              
  138.                 my $rss=new XML::RSS;
  139.                 eval {$rss->parsefile($file); };
  140.                 if( $@ ) {
  141.                     $@ =~ s/at \/.*?$//s;               # remove module line number
  142.                     print STDERR "\nERROR in '$file':\n$@\n";
  143.                 } else {
  144.                
  145. #-----------------------------------------------------------
  146. # Détection de la rubrique avec la méthode du module xml::rss, dans le cas ou il n'y a pas de rubrique ou classe le fichier dans les non-classés               
  147.                     my $rubrique=$rss->{'channel'}->{'title'};
  148.                     $rubrique=~s/é/e/gi;
  149.                     $rubrique=~s/è/e/gi;
  150.                     $rubrique=~s/ê/e/gi;
  151.                     $rubrique=~s/à/a/gi;
  152.                     $rubrique=~ s/Le ?Monde.fr ?://;
  153.                     $rubrique=~s/ ?- ?Le ?Monde\.fr//;
  154.                     $rubrique=~s/es$/e/i;
  155.                     $rubrique=~ s/ //g;
  156.                     $rubrique=uc($rubrique);
  157.                    
  158.                     if($rubrique eq ""){
  159.                     $rubrique = "NONCLASSE";
  160.                     }
  161.  
  162. #-----------------------------------------------------------
  163. # Création des fichiers de sortie                  
  164.                     open(OUT1,">>:encoding($encodagesortie)","./resultat/$rubrique.txt");
  165.                     open(OUT2,">>:encoding($encodagesortie)","./resultat/$rubrique.xml");
  166.                     open(OUT3,">>:encoding(utf-8)","./resultat/$rubrique-treetagger.xml");
  167.  
  168. #-----------------------------------------------------------
  169. # Ajout des entêtes dans les fichiers de sortie xml                
  170.                     if(-z OUT2){
  171.                         print OUT2 "<?xml version=\"1.0\" encoding=\"$encodagesortie\" ?>\n";
  172.                         print OUT2 "<file>\n";
  173.                         print OUT2 "<name>$rubrique</name>\n";
  174.                     }
  175.                    
  176.                     if(-z OUT3){   
  177.                     print OUT3 "<?xml version=\"1.0\" encoding=\"$encodagesortie\" ?>\n";
  178.                     print OUT3 "<file>\n";
  179.                     print OUT3 "<name>$rubrique</name>\n";
  180.                     }
  181.  
  182. #-----------------------------------------------------------
  183. # Détection de la date à l'aide des méthodes du module xml::rss, ajout de la date dans les fichiers de sortie xml      
  184. # Ajout de la balise items dans les fichiers de sortie xml             
  185.                     my $date=$rss->{'channel'}->{'pubDate'};
  186.                     print OUT2 "<date>$date</date>\n";
  187.                     print OUT2 "<items>\n";
  188.                     print OUT3 "<date>$date</date>\n";
  189.                     print OUT3 "<items>\n";
  190.  
  191. #-----------------------------------------------------------
  192. # Détection du titre et du résumé du fils rss à l'aide des méthodes du module xml::xmlrss                      
  193.                     foreach my $item (@{$rss->{'items'}}) {
  194.                         my $titre=$item->{'title'};
  195.                         my $resume=$item->{'description'};
  196.  
  197. #-----------------------------------------------------------
  198. # Test sur le titre du fil rss, si il est déjà contenu dans le tableau de hash on ne le traite pas
  199.                         my $test=$titre;
  200.                         if(!exists $tabcontenu{$test}){
  201.                        
  202. #-----------------------------------------------------------
  203. # Appel de la fonction "nettoietexte" avec comme paramétres le titre et le résumé
  204.                             $titre=&nettoietexte($titre);
  205.                             $resume=&nettoietexte($resume);
  206.                            
  207. #-----------------------------------------------------------
  208. # Conversion du titre et du résumé en utf-8 si l'encodage du fichier en entrée ne l'est pas
  209.                             if (uc($encodage) ne "UTF-8") {utf8($titre);utf8($resume);}
  210.                            
  211. #-----------------------------------------------------------
  212. # Appel de la fonction "etiquetage" avec comme paramétres le titre et le résumé
  213.                             my ($titreetiquete, $resumeetiquete) = &etiquetage ($titre, $resume);
  214.                            
  215. #-----------------------------------------------------------
  216. # On ajoute dans les différents fichiers le titre et le résumé
  217.                             print OUT1 "Titre : $titre \n";
  218.                             print OUT1 "Resume : $resume \n";;
  219.                             print OUT2 "<item><title>$titre</title><abstract>$resume</abstract></item>\n";
  220.                             print OUT3 "<item>\n<title>\n$titreetiquete</title>\n<abstract>\n$resumeetiquete</abstract>\n</item>\n";
  221.                            
  222. #-----------------------------------------------------------
  223. # On ajoute dans le tableau de hash le titre du fil rss
  224.                             $tabcontenu{$test}++;
  225.                             }
  226.                         }
  227.                        
  228. #-----------------------------------------------------------               
  229. # Fermeture de la balise items dans les fichiers xml, fermeture des fichiers
  230.                     print OUT2 "</items>\n";
  231.                     print OUT3 "</items>\n";
  232.                     close(OUT1);
  233.                     close(OUT2);
  234.                     close(OUT3);
  235.                     }
  236.                 }
  237.             }
  238.         }
  239.     }
  240. } # Fin "parcoursarborescencefichiers"
  241.  
  242.  
  243. #-----------------------------------------------------------
  244. # Fonction "etiquetage"
  245. # Permet d'etiqueter un texte avec le programme extérieur tree-tagger
  246. # Données : - $titre : une variable contenant des chaînes de caractères en utf-8
  247. #           - $resume : : une variable contenant des chaînes de caractères en utf-8
  248. # Résultats : 2 variables contenant le texte étiqueté par tree-tagger  
  249. sub etiquetage {
  250.     my ($titre,$texte)=@_;
  251.     #----- le titre
  252.     my $codage="utf-8";
  253.     my $tmptag="texteaetiqueter.txt";
  254.     open (TMPFILE,">:encoding(utf-8)", $tmptag);
  255.     print TMPFILE $titre,"\n";
  256.     close(TMPFILE);
  257.     system("perl ./treetagger-win32/cmd/tokenise-fr.pl $tmptag | tree-tagger.exe ./treetagger-win32/lib/french-utf8.par -lemma -token -no-unknown -sgml > treetagger.txt");
  258.    
  259.     system("perl ./treetagger-win32/cmd/treetagger2xml-utf8.pl treetagger.txt $codage ");
  260.     # lecture du resultat tagge en xml :
  261.     open(OUT,"<:encoding(utf-8)","treetagger.txt.xml");
  262.     my $fistline=<OUT>;
  263.     my $titreetiquete="";
  264.     while (my $l=<OUT>) {
  265.     $titreetiquete.=$l;
  266.     }
  267.     close(OUT);
  268.     #----- le resume
  269.     open (TMPFILE,">:encoding(utf-8)", $tmptag);
  270.     print TMPFILE $texte,"\n";
  271.     close(TMPFILE);
  272.     system("perl ./treetagger-win32/cmd/tokenise-fr.pl $tmptag | tree-tagger.exe ./treetagger-win32/lib/french-utf8.par -lemma -token -no-unknown -sgml > treetagger.txt");
  273.     system("perl ./treetagger-win32/cmd/treetagger2xml-utf8.pl treetagger.txt $codage");
  274.     # lecture du resultat tagge en xml :
  275.     open(OUT,"<:encoding(utf-8)","treetagger.txt.xml");
  276.     my $fistline=<OUT>;
  277.     my $texteetiquete="";
  278.     while (my $l=<OUT>) {
  279.     $texteetiquete.=$l;
  280.     }
  281.     close(OUT);
  282.     # on renvoie les resultats :
  283.     return ($titreetiquete,$texteetiquete);
  284. } # Fin "etiquetage"
  285.  
  286.  
  287. #-----------------------------------------------------------
  288. # Fonction "nettoietexte"
  289. # Nettoie un texte de ses entités xml
  290. # Donnée : une chaîne de caractère contenant des entités xml
  291. # Résultat : la chaîne de caractères nettoyée de ses entités xml
  292. sub nettoietexte {
  293.     my $texte=shift;
  294.     $texte =~ s/&lt;/</g;
  295.     $texte =~ s/&gt;/>/g;
  296.     $texte =~ s/<a href[^>]+>//g;
  297.     $texte =~ s/<img[^>]+>//g;
  298.     $texte =~ s/<\/a>//g;
  299.     $texte =~ s/&#38;#39;/'/g;
  300.     $texte =~ s/&#38;#34;/"/g;
  301.     $texte =~ s/&#233;/é/g;
  302.     $texte =~ s/&#234;/ê/g;
  303.     $texte =~ s/<[^>]+>//g;
  304.     $texte =~ s/&nbsp;/ /g;
  305.     $texte=~s/&#39;/'/g;
  306.     $texte=~s/&#34;/"/g;
  307.     $texte=~s/&amp;#39;/'/g;
  308.     $texte=~s/&amp;#34;/"/g;
  309.     return $texte;
  310. } # Fin "nettoietexte"
  311.  
  312.  
  313. #-----------------------------------------------------------
  314. # Procédure "decoupe"
  315. # Decoupe des fichiers de plus de 2Mo en plusieurs fichiers de 2Mo
  316. # Donnée : une variable contenant le nom d'un fichier à couper
  317. # Résultat : les fichiers découpés crées dans un répertoire "fichiers" contenu dans le répertoire "cordial"
  318. sub decoupe{
  319. my $fichier = shift(@_);
  320. open(F,"./cordial/$fichier");
  321. my $num = 1;
  322. my $taille = 0;
  323. while($ligne = <F>) {
  324.     if($taille < 2000000){ # On veut des fichiers de 2Mo = 2000000 octets
  325.     open (OUT,">>./cordial/fichiers/$fichier".$num.".txt");
  326.     print OUT $ligne;
  327.     $taille = -s OUT;
  328.     close(OUT);
  329.     }else{
  330.      $num++;
  331.      $taille = 0;
  332.     }
  333. }
  334. close (F);
  335. } # Fin "decoupage"
  336.