Pagination XSL

Récemment pour mon travail, j’ai travaillé sur une bibliothèque, dont je récupère le contenu en XML via une requête à une API. Ne voulant pas gérer la récupération du XML et son traitement en JavaScript, j’ai fait une pagination en XSL.

Le XSL est le CSS du XML. C’est donc une feuille de style, qui va déterminer comment afficher le contenu XML que j’ai reçu.

Je souhaitais n’afficher que un nombre prédéfinit de livres dans ma bibliothèque. Bien évidemment, l’API utilisée a des paramètres pour indiquer le nombre de livres à afficher, et la page que je veux afficher. Elle me renvoi aussi le nombre total de pages que j’aurais dans ma bibliothèque.

Grâce à tout ça je peux me faire une pagination ‘parfaite’.

Ce qu’il faut savoir avec le XSL, c’est que l’on ne peux pas faire de boucle. Mais on peux faire de la récursivité. La solution est donc de créer un template récursif qui va afficher mes numéros de page. Et pour corser le tout, je voudrais, si j’ai trop de pages, ne pas avoir un lien par page, mais par exemple ‘…’.

Cela donnerait quelque chose du genre :

1 2 3 … 5 6 7 8 9 … 16 17 18

Ma bibliothèque comportera donc 18 pages, et la page 7 est la page active.

Le code de pagination XSL

Voici le template. Il prend en paramètres :

  1. La page à afficher.
  2. La page en cours.
  3. Le nombre total de pages.
  4. Le nombre de page à montrer avant et après la page en cours.

Dans certaines ligne, il est écrit directement &gt; ou bien &lt;. C’est normal, il faut laisser comme ça, car XSLT n’aime pas qu’on mette directement le signe < ou > (qui servent pour les balises !).

<!-- Définition du nom du template -->
<xsl:template name="boucle">

    <!-- Les paramètres -->
    <xsl:param name="pageToShow"/><!-- Page à afficher -->
    <xsl:param name="currentPage"/><!-- Page en cours -->
    <xsl:param name="max"/><!-- Nombre total de pages -->
    <xsl:param name="windowSize"/><!-- Nombre de pages à afficher avant / après -->
    <xsl:param name="displayLeftDots"/><!-- Est-ce que les '...' ont déjà été affichés à gauche ou pas -->
    <xsl:param name="displayRightDots"/><!-- Est-ce que les '...' ont déjà été affichés à droite ou pas -->

    <!-- On test si on dois afficher le numéro de la page ou pas -->
    <!-- Et on stock le résultat (true / false) dans notre variable -->
    <xsl:variable name="displayCondition">
        <xsl:value-of select="$pageToShow < $windowSize or $pageToShow > $currentPage - $windowSize and $pageToShow < $currentPage+$windowSize or $pageToShow > $max - ($windowSize - 1)"/>
    </xsl:variable>

    <!-- Si on doit afficher le numéro de la page -->
    <xsl:if test="$displayCondition='true'">
        <xsl:choose>

            <!-- Si la page à afficher est la page en cours, on peux lui mettre un style different .. -->
            <xsl:when test="$pageToShow = $currentPage">
                <a href="javascript:void(0)" onclick="moveTo({$pageToShow});return false;" class="selected">
                    <span><xsl:value-of select="$pageToShow"/></span>
                </a>
            </xsl:when>

            <!-- Sinon on l'affiche simplement -->
            <xsl:otherwise>
                <a href="javascript:void(0)" onclick="moveTo({$pageToShow});return false;">
                    <span><xsl:value-of select="$pageToShow"/></span>
                </a>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>

    <!-- On créé une variable qui va nous dire si il faut afficher les points à gauche ou pas -->
    <xsl:variable name="leftDotsOn">

        <!-- Si nous n'avons pas affiché le numéro de la page -->
        <xsl:if test="$displayCondition='false'">

            <!-- Si la page à afficher est avant la page en cours, alors on dit d'afficher les points à gauche -->
            <xsl:if test="$pageToShow < $currentPage">
                <xsl:value-of select="not($displayLeftDots='false')"/>
            </xsl:if>

            <!-- Si la page à afficher n'est pas avant la page en cours, on dit de ne pas afficher les points à gauche -->
            <xsl:if test="not($pageToShow < $currentPage)">false</xsl:if>
        </xsl:if>

        <!-- Si on a affiché le numéro de la page, on n'affiche pas les points à gauche -->
        <xsl:if test="$displayCondition='true'">false</xsl:if>
    </xsl:variable>

    <!-- On créé une variable qui va nous dire si il faut afficher les points à droite ou pas -->
    <xsl:variable name="rightDotsOn">

        <!-- Si nous n'avons pas affiché le numéro de la page -->
        <xsl:if test="$displayCondition='false'">

            <!-- Si la page à afficher est après la page en cours, alors on dit d'afficher les points à droite -->
            <xsl:if test="$pageToShow > $currentPage">
                <xsl:value-of select="not($displayRightDots='false')"/>
            </xsl:if>

            <!-- Si la page à afficher n'est pas après la page en cours, on dit de ne pas afficher les points à droite -->
            <xsl:if test="not($pageToShow > $currentPage)">false</xsl:if>
        </xsl:if>

        <!-- Si on a affiché le numéro de la page, on n'affiche pas les points à droite -->
        <xsl:if test="$displayCondition='true'">false</xsl:if>
    </xsl:variable>

    <!-- Si on doit afficher les points, à gauche ou à droite -->
    <xsl:if test="$leftDotsOn='true' or $rightDotsOn='true'">
        <a href="javascript:void(0)"><span>...</span></a>
    </xsl:if>

    <!-- Si la page à afficher est plus petite que le  nombre total de pages -->
    <xsl:if test="number($pageToShow) < number($max)">

        <!-- On appel à nouveau le template, en incrémentant la valeur de $pageToShow -->
        <!-- Pour afficher la page suivante -->
        <xsl:call-template name="boucle">
            <xsl:with-param name="pageToShow" select="$pageToShow + 1"/>
            <xsl:with-param name="max" select="$max"/>
            <xsl:with-param name="currentPage" select="$currentPage"/>
            <xsl:with-param name="windowSize" select="$windowSize"/>

            <!-- Cette fois on lui passe en valeur le résultat de $leftDotsOn et $rightDotsOn -->
            <!-- Si ils sont à true, on a déjà affiché les points, et on ne les veux plus -->
            <xsl:with-param name="displayLeftDots" select="$displayLeftDots='true' or $leftDotsOn='true'"/>
            <xsl:with-param name="displayRightDots" select="$displayRightDots='true' or $rightDotsOn='true'"/>
        </xsl:call-template>
    </xsl:if>

</xsl:template>

Intégration

Voila, il ne reste plus qu’à appeler notre template à l’endroit où l’on souhaite avoir cette pagination XSL, en lui passant les bons paramètres. Dans notre exemple, on l’appellera comme ça :

<xsl:call-template name="boucle">
    <xsl:with-param name="pageToShow">1</xsl:with-param>
    <xsl:with-param name="currentPage" select="$pageNum"/>
    <xsl:with-param name="max" select="$pageCount"/>
    <xsl:with-param name="windowSize" select="$windowSize"/>
    <xsl:with-param name="displayLeftDots" select="false"/>
    <xsl:with-param name="displayRightDots" select="false"/>
</xsl:call-template>

Il va sans dire que vous aurez stockez avant dans des variables les infos qui vous interesse.. En l’occurence :

  • $pageNum : Numéro de la page en cours ( 7 dans notre exemple ).
  • $pageCount : Nombre total de pages ( 18 )
  • $windowSite : Nombre de pages à montrer avant / après ( 3 )
A lire aussi :  iPhone/iPad, doubleTap & Javascript

Voila vu comme ça, ça ne parait pas super compliqué, et pourtant ça l’est. Le langage XSL n’est pas vraiment simple à apprendre, ni intuitif. De plus je n’ai pas fait tout ça tout seul, je me suis beaucoup inspiré d’un code venant de l’utilisateur paquerette sur les forums Hardware.fr. Alors si tu me lis, ce dont je doute vraiment, merci !

4 réflexions sur “Pagination XSL

  • 8 octobre 2011 à 19:01
    Permalien

    « Le XSL est le CSS du XML. »

    En fait, XSL est composé de trois parties :
    * XPath permet de sélectionner des fragments de XML,
    * XSLT permet d’effectuer des transformations sur le XML,
    * et XSL-FO permet de formater le XML.
    On rapprochera donc CSS plutôt avec XSL-FO. 😉

    Répondre
  • 8 octobre 2011 à 19:11
    Permalien

    « Ce qu’il faut savoir avec le XSL, c’est que l’on ne peux pas faire de boucle. »

    En revanche, ce langage fournit tous les éléments pour construire toutes les boucles que tu souhaite :
    for, while, do, …

    Répondre
    • 4 novembre 2011 à 10:24
      Permalien

      Bonjour,

      Merci pour les précision.
      Je me suis mal exprimé en fait. On peux effectivement faire des boucles. Ce que l’on ne peux pas, c’est changer la valeur d’une variable. Ce ne sont que des constantes. D’où l’intérêt de la récursivité.

      Bonne journée.

      Répondre

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *