Documents Structurés
Site réalisé dans le cadre du cours de Documents Structurés par Kelly MASCLEF et Julie SAUVAGE.
Visiter le siteLe 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:
Les deux scripts d'extraction sont ceux fournis en cours légèrement modifiés (puisqu'ils fonctionnaient parfaitement!!).
Ce premier script récupère donc un patron ou une liste de patrons et lance les extractions.
#!/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:
#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
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.
#!/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; #
mkpath("./patternResults/"); open(PATTERNSFILE, $patterns_file) or die "can't open $patterns_file: $!\n";
while ($ligne =) { # on supprime avec la fonction chomp un éventuel retour à la ligne chomp($ligne); # $nb_patterns = push(@patterns,$ligne); }
my $xp = XML::XPath->new( filename => $tag_file ) or die "Problème";
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/"); }
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); }
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
Comme nous avons aussi utilisé l'étiquetage Cordial, nous avons procédé à une extraction de patrons sur les résultats Cordial.
#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 = ();
#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);
#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
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.
<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