1. <<DOC;
  2. Uyên-To DOAN-RABIER
  3. Ruixin HE
  4. Mohamed Sofiane KERROUA
  5.  
  6. BàO 2 - LibXML
  7.  
  8. En utilisant des expressions régulières et le module LibXML, 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_libxml.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::LibXML;
  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 converti 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. # Détection de la rubrique en mettant le texte sur une ligne, dans le cas ou il n'y a pas de rubrique ou classe le fichier dans les non-classés            
  138.                 open(FILE,"<:encoding($encodage)", $file);
  139.                 my $texte="";
  140.                 while (my $ligne=<FILE>) {
  141.                     $ligne =~ s/\n//g;
  142.                     $ligne =~ s/\r//g;
  143.                     $texte .= $ligne;
  144.                    
  145.                 }
  146.                 close(FILE);
  147.                
  148.                 if($texte =~/<channel><title>([^<]+)<\/title>/ig){
  149.                     $rubrique = $1;
  150.                     $rubrique=~s/é/e/gi;
  151.                     $rubrique=~s/è/e/gi;
  152.                     $rubrique=~s/ê/e/gi;
  153.                     $rubrique=~s/à/a/gi;
  154.                     $rubrique=~ s/Le ?Monde.fr ?://;
  155.                     $rubrique=~s/ ?- ?Le ?Monde\.fr//;
  156.                     $rubrique=~s/es$/e/i;
  157.                     $rubrique=~ s/ //g;
  158.                     $rubrique=uc($rubrique);
  159.                 }
  160.                
  161.                
  162.                 if($rubrique eq ""){
  163.                     $rubrique = "NONCLASSE";
  164.                 }
  165.                
  166. #-----------------------------------------------------------
  167. # Création des fichiers de sortie
  168.                 open(OUT1,">>:encoding(utf-8)","./resultat/$rubrique.txt");
  169.                 open(OUT2,">>:encoding(utf-8)","./resultat/$rubrique.xml");
  170.                 open(OUT3,">>:encoding(utf-8)","./resultat/$rubrique-treetagger.xml");
  171.  
  172. #-----------------------------------------------------------
  173. # Ajout des entêtes et de la balise item dans les fichiers de sortie xml
  174.                 if(-z OUT2){
  175.                     print OUT2 "<?xml version=\"1.0\" encoding=\"$encodagesortie\" ?>\n";
  176.                     print OUT2 "<file>\n";
  177.                     print OUT2 "<name>$ARGV[0]</name>\n";
  178.                 }
  179.                     if(-z OUT3){   
  180.                     print OUT3 "<?xml version=\"1.0\" encoding=\"$encodagesortie\" ?>\n";
  181.                     print OUT3 "<file>\n";
  182.                     print OUT3 "<name>$ARGV[0]</name>\n";
  183.                 }
  184.  
  185.                 print OUT2 "<items>\n";
  186.                 print OUT3 "<items>\n";
  187.  
  188. #-----------------------------------------------------------
  189. # Initialisation de la méthode du module xml::libxml               
  190.                 my $input_file= $file;
  191.                 my $parser = XML::LibXML->new();
  192.                 my $xp = $parser->parse_file($input_file);
  193.  
  194. #-----------------------------------------------------------
  195. # Détection de la date à l'aide des méthodes du module xml::libxml, ajout de la date dans les fichiers de sortie xml               
  196.                 my $date = "";
  197.                 foreach my $noeud_date ( $xp->findnodes('//channel')->get_nodelist ) {
  198.                     $date=$noeud_date->findnodes('//pubDate')->string_value;
  199.                     if (uc($encodage) ne "UTF-8") {utf8($date);}
  200.                 }
  201.                 print OUT2 "<date>$date</date>\n";
  202.                 print OUT3 "<date>\n$date</date>\n";
  203.  
  204. #-----------------------------------------------------------
  205. # Détection du titre et du résumé du fils rss à l'aide des méthodes du module xml::libxml              
  206.                 foreach my $noeud ( $xp->findnodes('//item')->get_nodelist ) {
  207.                     my $titre=$noeud->findnodes('title')->string_value;
  208.                     my $resume=$noeud->findnodes('description')->string_value;
  209.                    
  210. #-----------------------------------------------------------
  211. # Test sur le titre du fil rss, si il est déjà contenu dans le tableau de hash on ne le traite pas                 
  212.                     my $test=$titre;
  213.                     if(!exists $tabcontenu{$test}){
  214.                    
  215. #-----------------------------------------------------------
  216. # Conversion du titre et du résumé en utf-8 si l'encodage du fichier en entrée ne l'est pas
  217.                         if (uc($encodage) ne "UTF-8") {utf8($titre);utf8($resume);}
  218.                        
  219. #-----------------------------------------------------------
  220. # Appel de la fonction "nettoietexte" avec comme paramétres le titre et le résumé
  221.                         $titre=&nettoietexte($titre);
  222.                         $resume=&nettoietexte($resume);
  223.                        
  224. #-----------------------------------------------------------
  225. # Appel de la fonction "etiquetage" avec comme paramétres le titre et le résumé
  226.                         my ($titreetiquete, $resumeetiquete) = &etiquetage ($titre, $resume);
  227.                        
  228. #-----------------------------------------------------------
  229. # On ajoute dans les différents fichiers le titre et le résumé
  230.                         print OUT1 "Titre : $titre \n";
  231.                         print OUT1 "Resume : $resume \n";
  232.                         print OUT2 "<item><title>$titre</title><abstract>$resume</abstract></item>\n";
  233.                         print OUT3 "<item>\n<title>\n$titreetiquete</title>\n<abstract>\n$resumeetiquete</abstract>\n</item>\n";
  234.                      
  235. #-----------------------------------------------------------
  236. # On ajoute dans le tableau de hash le titre du fil rss
  237.                         $tabcontenu{$test}++;
  238.                     }
  239.                 }
  240.  
  241. #-----------------------------------------------------------               
  242. # Fermeture de la balise items dans les fichiers xml, fermeture des fichiers
  243.                 print OUT2 "</items>\n";
  244.                 print OUT3 "</items>\n";
  245.                 close(OUT1);
  246.                 close(OUT2);
  247.                 close(OUT3)
  248.             }
  249.         }
  250.         }
  251.     }
  252. }
  253.  
  254. #-----------------------------------------------------------
  255. # Fonction "etiquetage"
  256. # Permet d'etiqueter un texte avec le programme extérieur tree-tagger
  257. # Données : - $titre : une variable contenant des chaînes de caractères en utf-8
  258. #           - $resume : : une variable contenant des chaînes de caractères en utf-8
  259. # Résultats : 2 variables contenant le texte étiqueté par tree-tagger  
  260. sub etiquetage {
  261.     my ($titre,$texte)=@_;
  262.     #----- le titre
  263.     my $codage="utf-8";
  264.     my $tmptag="texteaetiqueter.txt";
  265.     open (TMPFILE,">:encoding(utf-8)", $tmptag);
  266.     print TMPFILE $titre,"\n";
  267.     close(TMPFILE);
  268.     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");
  269.    
  270.     system("perl ./treetagger-win32/cmd/treetagger2xml-utf8.pl treetagger.txt $codage ");
  271.     # lecture du resultat tagge en xml :
  272.     open(OUT,"<:encoding(utf-8)","treetagger.txt.xml");
  273.     my $fistline=<OUT>;
  274.     my $titreetiquete="";
  275.     while (my $l=<OUT>) {
  276.     $titreetiquete.=$l;
  277.     }
  278.     close(OUT);
  279.     #----- le resume
  280.     open (TMPFILE,">:encoding(utf-8)", $tmptag);
  281.     print TMPFILE $texte,"\n";
  282.     close(TMPFILE);
  283.     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");
  284.     system("perl ./treetagger-win32/cmd/treetagger2xml-utf8.pl treetagger.txt $codage");
  285.     # lecture du resultat tagge en xml :
  286.     open(OUT,"<:encoding(utf-8)","treetagger.txt.xml");
  287.     my $fistline=<OUT>;
  288.     my $texteetiquete="";
  289.     while (my $l=<OUT>) {
  290.     $texteetiquete.=$l;
  291.     }
  292.     close(OUT);
  293.     # on renvoie les resultats :
  294.     return ($titreetiquete,$texteetiquete);
  295. } # Fin "etiquetage"
  296.  
  297.  
  298. #-----------------------------------------------------------
  299. # Fonction "nettoietexte"
  300. # Nettoie un texte de ses entités xml
  301. # Donnée : une chaîne de caractère contenant des entités xml
  302. # Résultat : la chaîne de caractères nettoyée de ses entités xml
  303. sub nettoietexte {
  304.     my $texte=shift;
  305.     $texte =~ s/&lt;/</g;
  306.     $texte =~ s/&gt;/>/g;
  307.     $texte =~ s/<a href[^>]+>//g;
  308.     $texte =~ s/<img[^>]+>//g;
  309.     $texte =~ s/<\/a>//g;
  310.     $texte =~ s/&#38;#39;/'/g;
  311.     $texte =~ s/&#38;#34;/"/g;
  312.     $texte =~ s/&#233;/é/g;
  313.     $texte =~ s/&#234;/ê/g;
  314.     $texte =~ s/<[^>]+>//g;
  315.     $texte =~ s/&nbsp;/ /g;
  316.     $texte=~s/&#39;/'/g;
  317.     $texte=~s/&#34;/"/g;
  318.     $texte=~s/&amp;#39;/'/g;
  319.     $texte=~s/&amp;#34;/"/g;
  320.     return $texte;
  321. } # Fin "nettoietexte"
  322.  
  323.  
  324. #-----------------------------------------------------------
  325. # Procédure "decoupe"
  326. # Decoupe des fichiers de plus de 2Mo en plusieurs fichiers de 2Mo
  327. # Donnée : une variable contenant le nom d'un fichier à couper
  328. # Résultat : les fichiers découpés crées dans un répertoire "fichiers" contenu dans le répertoire "cordial"
  329. sub decoupe{
  330. my $fichier = shift(@_);
  331. open(F,"./cordial/$fichier");
  332. my $num = 1;
  333. my $taille = 0;
  334. while($ligne = <F>) {
  335.     if($taille < 2000000){ # On veut des fichiers de 2Mo = 2000000 octets
  336.     open (OUT,">>./cordial/fichiers/$fichier".$num.".txt");
  337.     print OUT $ligne;
  338.     $taille = -s OUT;
  339.     close(OUT);
  340.     }else{
  341.      $num++;
  342.      $taille = 0;
  343.     }
  344. }
  345. close (F);
  346. } # Fin "decoupage"
  347.