Documents Structurés

Site réalisé dans le cadre du cours de Documents Structurés par Kelly MASCLEF et Julie SAUVAGE.

Visiter le site

Projet Encadré 1

Programmation et Projet Encadré 1 du Semestre 1 par Kelly MASCLEF et Julie SAUVAGE (et avec Julie BELIAO).

Visiter le site

Projet Encadré 1

Programmation et Projet Encadré 1 du Semestre 1 par Ilaria TIDDI (avec Marcelo MATOSO et Camille DOUDANE).

Visiter le site

TAL

L5T53 / L5T55 (BASH/Emacs/Python) par Kelly MASCLEF

Visiter le site

Environnement-TAL

L5T53 / L5T55 (BASH/Emacs/Python) par Julie SAUVAGE

Visiter le site

Programmation pour le TAL avec PERL

L6T54 / L6T55 (PERL) par Julie SAUVAGE

Visiter le site

Bienvenue chez Perl

L6T54 / L6T55 (PERL) par Kelly MASCLEF

Visiter le site

Boîte à Outils 3

Le but de cette troisième boîte à outils est l'extraction de n'importe quels patrons syntaxiques. En effet, c'est à l'utilisateur de rentrer la suite de patrons qui l'intéresse afin de lancer le script à proprement dit.

Pour cela nous avons réalisé 3 scripts et une feuille de style:

  • Un premier script qui demande à l'utilisateur les patrons recherchés et qui lance les deux scripts d'extractions
  • Un script d'extraction des patrons pour le fichier TreeTagger
  • Un script d'extraction des patrons pour le fichier Cordial
  • Une feuille de style XSL utilisant des expressions XPATH
  • Les deux scripts d'extraction sont ceux fournis en cours légèrement modifiés (puisqu'ils fonctionnaient parfaitement!!).

    Script de lancement

    Ce premier script récupère donc un patron ou une liste de patrons et lance les extractions.

  • Récupération des patrons
  • #!/usr/bin/perl
    
    #On crée un fichier en sortie dans lequel nous allons stocker
    #les patrons désirés
    my $pattern_file="pattern.txt";
    open (OUT,">:encoding(utf-8)",$pattern_file);
    #Demande à l'utilisateur
    print "Donnez des patrons à extraire, un par ligne\n" 
    print "(STOP pour finir)\n";
    $ligne="..";
    #Jusqu'à ce que la variable $ligne contienne "STOP"…
    until ($ligne eq "STOP") {
    	#…on demande à l'utilisateur le patron désiré…
    	print "Patron (chaque terme séparé par un blanc) : ";
    	#…que l'on récupère à la sortie standard
    	$ligne=<STDIN>;
    	#On enlève le retour à la ligne
    	chomp($ligne);
    	#Si la variable $ligne contient "STOP"
    	if ($ligne ne "STOP") {
    		#On écrit les patrons récupérés dans le fichier
    		print OUT $ligne,"\n";
    		}
    	}
    #On ferme les tampons
    close (OUT);

    On aura alors dans la console:

    MmeJe-sais-tout@projet2 ~/projet-encadre2/trunk
    $ perl lancement_BaO3.pl
    Donnez des patrons à extraire, un par ligne
    (STOP pour finir)
    Patron (chaque terme séparé par un blanc) : NOM NOM ADJ
    Patron (chaque terme séparé par un blanc) : ADJ NOM ADJ
    Patron (chaque terme séparé par un blanc) : ADJ PREP ADJ
    Patron (chaque terme séparé par un blanc) : STOP
    Extracting…

  • Ensuite, on lance, via la commande system, l'extraction de patrons:
  • #On lance le script d'extraction via la commande 'system'
    #Pour TreeTagger
    system("perl ./bao3_rb_tt.pl Sortie_TreeTagger.xml $pattern_file");
    #Pour Cordial
    system("perl ./bao3_rb_cord.pl Sortie_Cordial.cnr.xml $pattern_file");

    Pour télécharger ce script, cliquez ici
    Pour visualiser ce script, cliquez ici

    [Haut de Page]

    Extraction de patrons pour Treetagger

    Ce deuxième script fait une extraction de patrons sur la sortie au format XML issue de la BàO2 grâce à un script perl.

  • On vérifie que l'utilisateur a mis les bons arguments pour le script perl :
  • #!/usr/bin/perl
    # usage : perl bao3_rb.pl fichier_tag fichier_motif
    # on appelle les bibliothèques
    use XML::XPath;
    use File::Copy;
    use File::Path;
    # On vérifie le nombre d'arguments de l'appel au script ($0 : le nom du script)
    if($#ARGV!=1){print "### ATTENTION ### usage : perl $0 fichier_tag fichier_motif ###\n";exit;}
    # Enregistrement des arguments dans les variables idoines
    my $tag_file= shift @ARGV;
    my $patterns_file = shift @ARGV;
    # Quelques initialisations fortes utiles
    my @patterns;
    my $nb_patterns=0;
    my $nb_tokens=0;
    #
    
    
  • On crée un dossier pour les résultats :
  • mkpath("./patternResults/");
    open(PATTERNSFILE, $patterns_file) or die "can't open $patterns_file: $!\n";
    
  • On lit le fichier .txt qui contient un patron par ligne ( par exemple NOM ADJ)
  • while ($ligne = ) {
    	# on supprime avec la fonction chomp un éventuel retour à la ligne
    	chomp($ligne);
    	# 
    	$nb_patterns = push(@patterns,$ligne);
    }
    
  • On crée l'objet XML::XPath pour explorer le fichier de sortie tree-tagger XML :
  • my $xp = XML::XPath->new( filename => $tag_file ) or die "Problème";
    
  • On exécute une recherche des patrons souhaités dans le fichier de sortie treetagger xml :
  • foreach my $pattern (@patterns){
    	# construction au moyen de la fonction split d'un tableau dont chaque élément a pour valeur  un token du motif recherché
    	@tokens=split(/ /,$pattern);
    	# définition du nom du fichier de sortie pour le motif en utilisant la fonction join
    	my $match_file = "res_extract-".join('_', @tokens).".txt";
    	open(MATCHFILE, ">$match_file") or die "can't open $match_file: $!\n";
    	# appel de la procédure d'extraction des formes correspondants au motif
    	&extract_pattern(@tokens);
    	close(MATCHFILE);
    	#on déplace le Matcfile qui vient d'être fermé dans un autre dossier
    	move($match_file,"./patternResults/");
    
    }
    
  • Une fois que les motifs ont été repérés on les extraits. Youpi !
  • sub extract_pattern{
    	@tokenz=@_;
    	# la fonction shift coupe le premier élement d'un tableau et le revoie en résultat
    	$first_token=shift @tokenz;
    	chomp($first_token);
    	# Initialisation du chemin xpath correspondant au motif recherché
    	# ATTENTION ici aux effets de bord dus à la structure choisie pour le fichier tree-tagger XML
    	# par exemple pour le motif NOM ADJ : une description d'un fil rss qui se termine par un NOM suivie d'une autre description qui commence par un ADJ !
    	$search_path="//element/data[1][contains(text(),\"$first_token\")]";
    	foreach my $token (@tokenz){# construction  recursive du chemin xpath correspondant au motif recherché
    		chomp($token);
    		$search_path.="/ancestor::element/following-sibling::element[1]/data[1][contains(text(),\"$token\")]";
    	}
    	# boucle sur les nœud s reconnus du chemin xpath
    	# c'est ici qu'on rentre dans le clou du programme
    	#sur l'objet mynoeud on appelle la fonction FIND= elle cherche le chemin $search_path et collecte tous les blocs fils
    	#getnodelist retourne une liste de noeuds 
    	foreach my $noeud ( $xp->find($search_path)->get_nodelist ) {
    		# initialisation du tableau des formes
    		# on le fait ici pour des raisons évidentes d'économie de mémoire et donc de performance
    		my @matching_tokens;
    		# on remonte d'un cran au nœud  parent pour extraire la forme trouvée
    		# dans le cas d'un motif NOM ADJ, c'est la forme de l'adjectif qu'on atteint
    		# getParentNode donne le noeud parent
    		$noeud_tmp=$noeud->getParentNode;
    		$i=0;
    		foreach (@tokens){
    			$i++;
    			# on récupère la forme
    			# noter que le "3" de getChildNode(3) correspond au "data[3]" de la feuille XSLT
    			$motif=$noeud_tmp->getChildNode(3)->string_value;
    			# unshift(@matching_tokens,$motif) ajoute au début du tableau @matching_tokens un élément dont la valeur est le contenu de la variable $motif
    			$nb_tokens=unshift(@matching_tokens,$motif);
    			$motif="";
    			# on remonte recursivement aux nœuds précedents pour extraire la forme
    			# dans le cas d'un motif NOM PRP NOM, on récupère ainsi PRP puis NOM (le premier)
    			# noter que "precding-sibling" est l'axe inverse de "following-sibling"
    			@noeudtmp=$xp->find("./preceding-sibling::element[1]",$noeud_tmp)->get_nodelist;
    			$noeud_tmp=shift(@noeudtmp);
    		}
    
  • On écrit les résultats dans un fichier
  • print MATCHFILE join(' ', @matching_tokens)."\n";
    

    Pour télécharger ce script, cliquez ici
    Pour télécharger le paquet des résultats (Cordial et TreeTagger), cliquez ici
    Pour visualiser ce script, cliquez ici

    [Haut de Page]

    Extraction de patrons pour Cordial

    Comme nous avons aussi utilisé l'étiquetage Cordial, nous avons procédé à une extraction de patrons sur les résultats Cordial.

  • On a tout d'abord les opérations préalables comme l'ouverture des fichiers, création des listes, etc.
  • #On ouvre les deux fichiers en lecture et le fichier en écriture
    open (FICTAG, $ARGV[0]) or die ("probleme sur ouverture de la sortie CORDIAL...");
    open (FICPOS, $ARGV[1]) or die ("probleme sur ouverture du fichier des patrons...");
    open (OUT, "> resultats_$ARGV[0].txt") or die ("probleme sur ouverture du fichier de sortie...");
    #Stockage des patrons
    my @listedespatrons=();
    while (my $lignepos = ) {
        chomp($lignepos);
        push(@listedespatrons,$lignepos);
    }
    close(FICPOS);
    #On initialise les listes
    my @malignesegmentee = ();
    my @listedetokens = ();
    my @listedelemmes = ();
    my @listedepos = ();
  • Puis on traite le fichier étiqueté:
  • #On lit le fichier ligne par ligne
    while (my $ligne = ) {
        #On récupère les lignes correpondant au bon format
        if ($ligne =~ /^[^\t]+\t[^\t]+\t[^\t]+$/) {
    	#On supprime le retour à la ligne
    	chomp($ligne);
    	#On insére les éléments dans les listes
    	@malignesegmentee = split(/\t/, $ligne);
    	push(@listedetokens, $malignesegmentee[0]);
    	push(@listedelemmes, $malignesegmentee[1]);
    	push(@listedepos, $malignesegmentee[2]);
        }
    }
    close(FICTAG);
  • On va maintenant pouvoir parcourir les tokens et les POS afin de récupérer les patrons:
  • #Création d'une liste temporaire des POS 
    #(qu'on supprimera au fur et à mesure si pas de résultat)
    my @tmplistedespos=@listedepos;
    my $indice=0;
    while (my $a =shift(@tmplistedespos)) {
    	#Pour chaque patron dans la liste des patrons
        foreach my $patron (@listedespatrons) {
    	#On récupère le premier élément du patron
    	my @listedeterme=split(/\#/,$patron);
    	#Si l'élément analysé correpond au patron
    	if ($a=~/$listedeterme[0]/) {
    	    #On vérifie que la suite correspond au patron
    	    my $verif=0;
    	    for (my $i=0;$i<=$#listedeterme-1;$i++) {
    		if ($tmplistedespos[$i]=~/$listedeterme[$i+1]/) { 
    		    $verif++ ;
    		}
    		else {
    			#la liste des POS ne correspond pas aux tokens
    		}
    	    }
    	    #Si on a reconnaissance, on récupère le résultat
    	    if ($verif == $#listedeterme) { 
    		#print "Correspondance sur $patron \n";
    		for (my $i=0;$i<=$#listedeterme;$i++) {
    		    print OUT $listedetokens[$indice+$i]," ";
    		}
    		print OUT "\n";
    	    }
    	}
        }
        $indice++;
    }

    Pour télécharger ce script, cliquez ici
    Pour télécharger le paquet des résultats (Cordial et TreeTagger), cliquez ici
    Pour visualiser ce script, cliquez ici

    [Haut de Page]

    Extraction de patrons XSLT:XPATH

    Ayant très largement utilisé les feuilles de style XSL pour le projet de Documents Structurés, nous avons procédé à l'extraction de certains patrons (afin d'exemplifier chaque méthode) dans un petit extrait du fichier taggé et au format XMl Treetagger.

    • On applique les templates rules dans le corps du document.
    • On crée un template rule pour la recherche de patrons.
    • On crée autant de boucle if que l'on a de patrons.
    • On recherche le premier élément du patron, on le stocke dans une variable.
    • Si après cet élément, on a encore un élément désiré on le stocke dans une nouvelle variable. Pour cela, on est allé au noeud suivant l'élément précédent en testant le contenu.
    • Il ne reste plus qu'à se servir des variables pour rétablir le contenu désiré.
    <xsl:template match="document">
    <h2><a name="npan">Patron NOM PRP ADJ NOM</a></h2>
    <p class="dashed">
    <xsl:for-each select="article/element">
    	<xsl:if test="(./data[contains(text(),'NOM')])">
    		<xsl:variable name="a1" select="./data[3]/text()"/>
    	<xsl:if test="following-sibling::element[1][./data[contains(text(),'PRP')]]">
    		<xsl:variable name="a2" select="following-sibling::element[1]/data[3]/text()"/>
    	<xsl:if test="following-sibling::element[2][./data[contains(text(),'ADJ')]]">
    		<xsl:variable name="a3" select="following-sibling::element[2]/data[3]/text()"/>
    	<xsl:if test="following-sibling::element[3][./data[contains(text(),'NOM')]]">
    		<xsl:variable name="a4" select="following-sibling::element[3]/data[3]/text()"/>
    		<span class="nom"><xsl:value-of select="$a1"/></span><xsl:text> </xsl:text>
    		<span class="prp"><xsl:value-of select="$a2"/></span><xsl:text> </xsl:text>
    		<span class="adj"><xsl:value-of select="$a3"/></span><xsl:text> </xsl:text>
    		<span class="nom"><xsl:value-of select="$a4"/></span><br />
    	</xsl:if>
    	</xsl:if>
    	</xsl:if>
    	</xsl:if>
    </xsl:for-each>
    </p>
    </xsl:template>

    Pour télécharger la feuille de style, cliquez ici
    Pour visualiser la feuille de style, cliquez ici
    Pour visualiser le résultat, cliquez ici


    [Haut de Page]