#/usr/bin/perl
<<DOC; 
-------------------------------------------------------------------------
Nom : Aurore LESSIEUX & Corentin VIALAR
Date : AVRIL 2020
Action : parcours une arborescence de fil RSS, extrait, nettoie et étiquete (avec TreeTagger et Talismane) les contenus textuels des titres et des descriptions en utilisant l arborescence du fichier XML avec la bibliothèque perl XML::RSS.

Commande de lancement : perl bao2_v-perl_xmlrss.pl REPERTOIRE_A_PARCOURIR RUBRIQUE_A_EXTRAIRE

ENTREE : le programme prend en entrée le nom du répertoire contenant les fichiers à traiter + la rubrique 
SORTIE : le programme crée en sortie 3 fichiers :
		- Un fichier au format texte brute (pareil à BAO1)
		- Un fichier au format texte brute (txt), contenant le texte issu du fitrage étiqueté avec Talismane
		- Un fichier structuré au format XML, contenant le contenu textuel du résultat du filtrage étiqueté avec TreeTagger :			
			<BAO_2>
				<NOM>du fichier</NOM>
				<fichiers>contenu du filtrage étiqueté avec TreeTagger</fichiers>
			</BAO_2>
-------------------------------------------------------------------------
DOC
#----------------------------------------------------------------------
#Appel de la bibliothèque XML::RSS
use XML::RSS;
#Utilisation de XML::RSS :
my $rss=new XML::RSS;

#On récupère dans 2 variables les arguments passés au programme :
my $rep="$ARGV[0]";	#pour le répertoire à traiter
my $rubrique = "$ARGV[1]";	#la rubrique souhaitée

#variable qui prendra l'ensemble des titres et descriptions pour l'étiquetage avec Talismane :
my $titre_desc_global = "";

# on s'assure que le nom du répertoire ne se termine pas par un "/"
$rep=~ s/[\/]$//;

#-----------------------------------------------------------

#on déclare et ouvre les fichiers de sortie en mode écriture :
open(OUT,">:encoding(utf8)", "BAO2_sortie_$rubrique.txt"); 
open(OUTXML, ">:encoding(utf8)", "BAO2_sortiexml_$rubrique.xml");
open(OUTTALISMANE, ">:encoding(utf8)", "BAO2_sortietalismane_$rubrique.txt");

#on écrit la tête du fichier XML :
print OUTXML "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
print OUTXML "<BAO_2>\n"; #Déclaration de la racine
#les auteurs
print OUTXML "\t<auteur>Aurore LESSIEUX</auteur>\n"; 
print OUTXML "\t<auteur>Corentin VIALAR</auteur>\n";
print OUTXML "\t<NOM>Rubrique : $rubrique</NOM>\n";

#l'ensemble des données extraites
print OUTXML "<fichiers>\n";

#on initialise un compteur et une table de hachage (dictionnaire en python) pour traiter les éventuels doublons :
my %dico_des_titres =();
my $i = 0;


#-----------------------------------------------------------
#Appel d'un sous-programme qui va parcourir l'arborescence de manière récursive :
#on passe le repertoire contenant les fichiers à traitées en argument du sous-programme
&parcoursarborescencefichiers($rep);

#sous-programme qui étiquete un fichier global contenant l'ensemble des titres et des descriptions avec Talismane :
&etiquetageTALISMANE($titre_desc_global);
#-----------------------------------------------------------
#fermeture des fichiers :
close(OUT); #fermeture du fichier texte
close(OUTTALISMANE); #fermeture du fichier Talismane

print OUTXML "\t</fichiers>\n";
print OUTXML "</BAO_2>\n";
close(OUTXML); #fermeture du fichier XML

exit;

#-----------------------------------------------------------

#Le sous-programme qui prend en argument le répertoire à traiter:
#(sous-programmemme récursif)
sub parcoursarborescencefichiers {
	#---on récupère la racine du chemin
	#shift prend le premier élément de la liste et le renvoie :
	my $path = shift(@_);
	
	#---ouverture du contenue du répertoire :
	#on sait que la racine est un dossier donc utilisation d'"opendir"
	opendir(DIR, $path) or die "can't open $path: $!\n";
	
	#---lecture du répertoire :
	#renvoie une liste de ressource du répertoire
	my @files = readdir(DIR);#examiner la liste de ressource
	
	#fermeture du répertoire :
	closedir(DIR);
	
	#boucle sur chacun des éléments de la liste des ressources du répertoire:
	foreach my $file (@files) {	
		#on passe au fichier suivant si le fichier est caché : "." ou ".." ; sinon on risque de créer une boucle sur le répertoire courant
		next if $file =~ /^\.\.?$/;
		
		#reconstruction du chemin relatif où l'on se trouve :
		$file = $path."/".$file;
		
		#si le chemin relatif conduit à un répertoire :
		# -d permet de vérifier que $file est un répertoire
		if (-d $file) {	
			#si on est dans un répertoire, on recommence toute la procédure avec un nouveau chemin passé en argument :
			&parcoursarborescencefichiers($file);	#recurse!
		}
		
		#si le chemin relatif conduit à un fichier :
		#-f permet de vérifier que $fil est un fichier
		if (-f $file) {	
			#----------TRAITEMENT à réaliser sur chaque fichier----------------------------------------------
			
			#---Lecture du fichier :
			#si le fichier a une EXTENSION XML et la RUBRIQUE passé en argument au programme :
			if ($file =~/$rubrique.+\.xml$/) {
				#incrémentation du compteur, message dans la console :
				print $i++, "Traitement de :", $file, "\n";
				print "##------------------------------------------##\n";
				
#---BAO1 : perl - XML::RSS-----------------------------------------------------------------------------
				#---on parse le fichier :
				eval {$rss->parsefile($file);};
				#si il y a eu erreur
				if( $@ ) {     
					$@ =~ s/at \/.*?$//s; # remove module line number
					print STDERR "\nERROR in '$file':\n$@\n";
				}
				
				#---Extraction :
				else {
					foreach my $item (@{$rss->{'items'}}) {
						#on extrait le titre
						my $titre = $item->{'title'};
						#on extrait la description
						my $description = $item->{'description'};			

#------------------------------------------------------------------------------------------------------	
					
						#---Traitement des doublons :
						#si le titre n'existe pas dans le dictionnaire $dico_des_titres :
						if (!(exists $dico_des_titres{$titre} )) {
							#alors il n'y a pas de doublon et on effectue le traitement suivant :
						
							#on ajoute le titre et la description au dictionnaire
							$dico_des_titres{$titre}=$description ; 
									
							#---Nettoyage du texte :
							#A l'aide d'un autre sous-programme on nettoie les "cochonneries" des contenues textuelles qu'on a extrait
							($titre, $description) = &nettoyage($titre, $description);
						
#------BAO2 : Etiquetage avec TreeTagger---------------------------------------------------
							#---Concaténation des titres et descriptions nettoyés (pour le sous-programme d'étiquetage avec Talismane :
						
							$titre_desc_global = $titre_desc_global.$titre."\n";
							$titre_desc_global = $titre_desc_global.$description."\n";

							#---Etiquetage du texte : avec TreeTagger > on renvoit à une procédure
							my($titre_POS, $description_POS) = &etiquetage($titre, $description);

							#Ecriture des fichiers de sortie :
							#------------VERSION TXT---------------------
							print OUT "TITRE : ", $titre,"\n";
							print OUT "DESCRIPTION :", $description,"\n";
							print OUT "-------\n";
						
							#------------VERSION XML---------------------
							print OUTXML "\t\t<item>\n" ;
							print OUTXML "\t\t\t<titre>$titre_POS</titre>\n";
							print OUTXML "\t\t\t<description>$description_POS</description>\n";
							print OUTXML "\t\t</item>\n";
						
							#message dans la console :
							print "$file est le", $i++,"\n";
						
							#si le titre existe déjà dans le dictionnaire, on ne fait rien
						}
					}
				}
			}
		}
	}
}
#--------------BAO2 : Etiquetage avec Talismane-------------------------------------
sub etiquetageTALISMANE {
	my $titre_desc_global = $_[0];
	#---Etiquettage du texte : avec Talismane > utilisation de la variable $titre_desc_global :
	#création et ouverture en mode écriture d'un fichier temporaire qui va prendre le contenu textuel :
	open (TALIS, ">:encoding(utf8)", "bao2_talismane_temporaire.txt");
	print TALIS $titre_desc_global;
	close TALIS;
				
	#commande système ; on fait appel à un script java pour étiqueter le contenu textuel avec Talismane :
	system ("java -Xmx1G -Dconfig.file=../TALISMANE/talismane-fr-5.0.4.conf -jar ../TALISMANE/talismane-core-5.1.2.jar --analyse --sessionId=fr --encoding=UTF8 --inFile=bao2_talismane_temporaire.txt --outFile=bao2_talismane_temporaire.tal");
				
	#---ouverture du fichier avec les résultats étiquetés avec Talismane :
	open (TEMP, "<:encoding(utf8)", "bao2_talismane_temporaire.tal");
	#la variable resultat_talismane prend pour valeur le contenu du fichier
	$resultat_talismane = <TEMP>;
	close TEMP;
				
	#---intégration de l'étiquetage Talismane dans le fichier Talismane final :
	print OUTTALISMANE $resultat_talismane;	
}

#--------------------------------------------------------------------------------

#le sous programme qui nettoie le contenu textuel extrait :
#Entrée : 2 variables textuelles
#Sortie : les 2 variables textuelles nettoyées
sub nettoyage {
	#récupérer ce qui a été passé en argument au programme : @ARGV 
	my $titre = $_[0];
	my $description = $_[1];
	
	#---Nettoyage :
	#enlever les structures [CDATA[ ... ]]	
	$description=~s/^<;!\[CDATA\[//;
	$description=~s/\]\]&gt;$//;
	$titre=~s/^<;!\[CDATA\[//;
	$titre=~s/\]\]&gt;$//;
	
	#rempalcer le code par des guillemets simples :
	$description =~s/&#38;#39;/'/g;
	$titre =~s/&#38;#39;/'/g;
	
	#remplacer le code par des guillemets doubles :
	$description =~s/&#38;#34;/"/g;
	$titre =~s/&#38;#34;/"/g;
	
	#suppresion des balises
	$description =~s/&lt;.+?&gt;//g ;
	$titre =~s/&lt;.+?&gt;//g ;
	
	#remplacer & par "et":
	$description =~s/&/et/g ;
	$titre =~s/&/et/g ;
	
	#rajouter un point à la fin des titres
	$titre=~s/$/\./g;
	
	#renvoyer le contenu textuel nettoyé :
	return $titre, $description;
}


#---------------------------------------------------
#sous-programme pour étiqueter le contenu textuel des titres et des descriptions avec TreeTagger :
#Entrée : 2 variables textuelles ($titre et $description)
#Sortie : les 2 variables textuelles étiquetés avec TreeTagger au format XML
sub etiquetage {
	#répération des variables mises en argument :
	my $titre = $_[0];
	my $description = $_[1];
	
	#---Traitement de TITRE :
	#création et ouverture en écriture d'un fichier temporaire où l'on met la chaîne à traiter :
	open (TEMP, ">:encoding(utf8)", "temporaire.txt");
	print TEMP $titre;
	close TEMP;
	
	#---Tokenisation + Etiquettage TreeTagger de temporaire.txt > fic_tagg.txt.pos
	#on fait appel à un autre script perl pour tokeniser puis tagger en POS TreeTagger le contenu du fichier temporaire.
	#sortie des résultats dans le fichier fic_tagg.txt.pos
	#commande système = on invoque la fenêtre de traitement et on envoie la commande au système pour qu'il l'exécute :
	system ("perl -f tokenise-utf8.pl  temporaire.txt  |./tree-tagger.exe french-oral-utf-8.par -token -lemma -no-unknown > fic_tagg.txt.pos");
	
	#---Mise en forme XML de l'étiquetage :
	#mise en application d'un second script perl pour mettre le résultat de l'étiquetage au format XML:
	system ("perl treetagger2xml-utf8.pl fic_tagg.txt.pos utf8");
	
	#ouverture en lecture du fichier avec le résultat :
	open (TAGG, "<:encoding(utf8)", "fic_tagg.txt.pos.xml");
	#lecture du fichier dans sa globalité
	$/=undef;
	#la variable $titre_etik_XML prend comme valeur le contenu du fichier
	my $titre_etik_XML = <TAGG>;
	close TAGG;
	
	
	#---Traitement de DESCRIPTION :
	#on refait la même chose pour la description :
	open (TEMP, ">:encoding(utf8)", "temporaire.txt");
	print TEMP $description;
	close TEMP;
	
	system ("perl -f tokenise-utf8.pl  temporaire.txt  |./tree-tagger.exe french-oral-utf-8.par -token -lemma -no-unknown > fic_tagg.txt.pos");
	system ("perl treetagger2xml-utf8.pl fic_tagg.txt.pos utf8");
	
	open (TAGG, "<:encoding(utf8)", "fic_tagg.txt.pos.xml");
	$/=undef;
	my $description_etik_XML = <TAGG>;
	close TAGG;
	
	#---Nettoyage des résultats : on retire les balises ouvrante et fermantes de la déclaration XML :
	$titre_etik_XML =~s/<\?xm[^>]+>//;
	$description_etik_XML =~s/<\?xm[^>]+>//;
	
	#on retourne le résultat :
	return $titre_etik_XML, $description_etik_XML;
	
}