Liste de tokens


Exemple : sortie XML d'un étiqueteur :
<?xml version="1.0" encoding="iso-8859-1"?>
<doc>
    <taggersent>
        <taggertoken wordform="Il" lemma="il" pos="PRO"/>
        <taggertoken wordform="était" lemma="être" pos="VER:sg"/>
        <taggertoken wordform="une" lemma="un" pos="DET:femi:sg"/>
        <taggertoken wordform="fois" lemma="fois" pos="NOM:femi:sg"/>
        <taggertoken wordform="," lemma="," pos="PUN"/>
        <taggertoken wordform="les" lemma="le" pos="DET:masc:pl"/>
        <taggertoken wordform="voleurs" lemma="voleur" pos="NOM:masc:pl"/>
        <taggertoken wordform="étaient" lemma="étayer|être" pos="VER:pl"/>
        <taggertoken wordform="dans" lemma="dans" pos="PRP"/>
        <taggertoken wordform="la" lemma="le" pos="DET:femi:sg"/>
        <taggertoken wordform="forêt" lemma="forêt" pos="NOM:femi:sg"/>
        <taggertoken wordform="." lemma="." pos="PUN"/>
    </taggersent>
    <taggersent>
        <taggertoken wordform="Ils" lemma="il" pos="PRO"/>
        <taggertoken wordform="étaient" lemma="étayer|être" pos="VER:pl"/>
        <taggertoken wordform="tous" lemma="tout" pos="PRO"/>
        <taggertoken wordform="assis" lemma="asseoir" pos="VER:pper:masc:pl"/>
        <taggertoken wordform="autour" lemma="autour" pos="ADV"/>
        <taggertoken wordform="du" lemma="du" pos="PRP:DET:masc:sg"/>
        <taggertoken wordform="feu" lemma="feu" pos="NOM:masc:sg"/>
        <taggertoken wordform="." lemma="." pos="PUN"/>
    </taggersent>
</doc>
Objectif : extraire la liste des tokens (forme orthographique) triée dans l'ordre alphabétique.
XSL Résultat
<xsl:template match="/">
    <xsl:for-each select="//taggertoken">
        <xsl:sort select="@wordform" order="ascending"/>
        <xsl:value-of select="@wordform"/>
        <xsl:text>
        </xsl:text>
    </xsl:for-each>
</xsl:template>
  
,
.
.
assis
autour
dans
du
étaient
étaient
était
feu
fois
forêt
Il
Ils
la
les
tous
une
voleurs

Tricky...

Comment faire en sorte que chaque forme n'apparaīsse qu'une seule fois ?
  1. <xsl:template match="/">
  2.     <xsl:for-each select="//taggertoken">
  3.         <xsl:sort select="@wordform" order="ascending"/>
  4.         <xsl:apply-templates select=".">
  5.             <xsl:with-param name="pos"><xsl:value-of select="position ()"/></xsl:with-param>
  6.         </xsl:apply-templates>
  7.     </xsl:for-each>
  8. </xsl:template>
  9. <xsl:template match="taggertoken">
  10.     <xsl:param name="pos"/>
  11.     <xsl:variable name="prevForm">
  12.         <xsl:for-each select="//taggertoken">
  13.             <xsl:sort select="@wordform" order="ascending"/>
  14.                 <xsl:if test="position()=number($pos - 1)">
  15.                     <xsl:value-of select="@wordform"/>
  16.                  </xsl:if>
  17.         </xsl:for-each>
  18.     </xsl:variable>
  19.     <xsl:if test="normalize-space(string($prevForm)) != normalize-space(string(@wordform))">
  20.         <xsl:value-of select="@wordform"/>
  21.         <xsl:text>
  22.         </xsl:text>
  23.      </xsl:if>
  24. </xsl:template>
  
,
.
assis
autour
dans
du
étaient
était
feu
fois
forêt
Il
Ils
la
les
tous
une
voleurs
Commentaires :
  • lignes 2 et 3, on sélectionne tous les tokens par ordre croissant de forme
  • pour chacun de ces tokens, on applique le template correspondant (taggertoken) en lui passant comme paramètre la position du token. Cette position n'est pas relative à la structure de l'arbre initiale mais à celle des tokens triés par le for-each.
  • comme nous voulons l'unicité des formes des tokens, nous devons déterminer la forme du token précédent dans le même ordre que celui construit aux lignes 1 et 2. Nous construisons ainsi (lignes 14 à 21), une varaible prevForm dans laquelle nous recréons la même boucle for-each qu'aux lignes 1 et 2 (ce qui est peu élégant...) en sélectionnant la forme du token dont la position vaut celle passée en paramètre - 1,
  • enfin, nous affichons la forme du mot si la forme précédente n'est pas identique.
  • l'usage de l'élément text aux lignes 25 et 26 est un moyen de générer un retour-charriot en sortie.

La même chose, avec une table de fréquences :
<xsl:template match="/">
    <xsl:for-each select="//taggertoken">
        <xsl:sort select="@wordform" order="ascending"/>

        <xsl:apply-templates select=".">
            <xsl:with-param name="pos"><xsl:value-of select="position ()"/></xsl:with-param>
        </xsl:apply-templates>
    </xsl:for-each>
</xsl:template>

<xsl:template match="taggertoken">
    <xsl:param name="pos"/>

    <xsl:variable name="prevForm">
        <xsl:for-each select="//taggertoken">
            <xsl:sort select="@wordform" order="ascending"/>
                <xsl:if test="position()=number($pos - 1)"><xsl:value-of select="@wordform"/></xsl:if>
        </xsl:for-each>
    </xsl:variable>

    <xsl:if test="normalize-space(string($prevForm)) != normalize-space(string(@wordform))">
        <xsl:value-of select="@wordform"/>
        <xsl:text> </xsl:text>
        <xsl:value-of select="count(//taggertoken[@wordform=current()/@wordform])"/>
        <xsl:text>
        </xsl:text>
    </xsl:if>
</xsl:template>
  
, 1
. 2
assis 1
autour 1
dans 1
du 1
étaient 2
était 1
feu 1
fois 1
forêt 1
Il 1
Ils 1
la 1
les 1
tous 1
une 1
voleurs 1 
Le problème revient au même : sélectionner les formes des tokens en gardant l'unicité et compter pour chaque forme le nombre d'apparitions dans le document (solution toujours peu élégante : cela fait en tout 3 itérations imbriquées sur tous les tokens du document !)
À noter : l'expression @wordform=current()/@wordform 
nous voulons comparer l'attribut wordform de l'élément courant à l'attribut wordform de l'élément désigné par l'expression XPath //taggertoken. Or dans ce cas, @wordform ou ./@wordform (équivalents) sont relativs à //taggertoken. L'expression current() permet de désigner l'élément en cours de traitement.

Précédent... ] Sommaire... ] Suivant... ]