web-dev-qa-db-fra.com

XSLT: Boucle de 1 à 60

Quel est le meilleur moyen de boucler le XSLT de 1 à 60? Je fais des recherches dans le réseau, il existe quelques modèles pour le faire, existe-t-il un autre moyen, par exemple une fonction intégrée?

31
Ianthe

Dans XSLT 2.0,

<xsl:for-each select="1 to 60">...</xsl:for-each>

Mais je suppose que vous devez utiliser XSLT 1.0, sinon vous ne le feriez pas.

Dans XSLT 1.0, vous devez utiliser la récursivité: un modèle qui s’appelle avec un compteur incrémenté à chaque appel et qui se termine lorsque la valeur requise est atteinte.

XSLT 1.0 offre également une solution de contournement: si votre document source contient au moins 60 nœuds, vous pouvez le faire.

<xsl:for-each select="(//node())[60 >= position()]">...</xsl:for-each>
42
Michael Kay

Le problème de la récursivité simple lors du traitement de longues séquences est que l'espace pour la pile d'appels devient souvent insuffisant et que le traitement se termine en raison d'un débordement de pile. Cela se produit généralement avec une longueur de séquence> = 1000.

Une technique générale pour éviter cela (implémentable avec tout processeur XSLT, même s'il ne reconnaît pas la récursion de la queue) est la récursion de style DVC (Divide and Conquer) .

Voici un exemple de transformation qui imprime avec succès les nombres de 1 à 1000000 (1M):

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output method="text"/>

     <xsl:template match="/">
      <xsl:call-template name="displayNumbers">
        <xsl:with-param name="pStart" select="1"/>
        <xsl:with-param name="pEnd" select="1000000"/>
      </xsl:call-template>
     </xsl:template>

     <xsl:template name="displayNumbers">
      <xsl:param name="pStart"/>
      <xsl:param name="pEnd"/>

      <xsl:if test="not($pStart > $pEnd)">
       <xsl:choose>
        <xsl:when test="$pStart = $pEnd">
          <xsl:value-of select="$pStart"/>
          <xsl:text>&#xA;</xsl:text>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="vMid" select=
           "floor(($pStart + $pEnd) div 2)"/>
          <xsl:call-template name="displayNumbers">
           <xsl:with-param name="pStart" select="$pStart"/>
           <xsl:with-param name="pEnd" select="$vMid"/>
          </xsl:call-template>
          <xsl:call-template name="displayNumbers">
           <xsl:with-param name="pStart" select="$vMid+1"/>
           <xsl:with-param name="pEnd" select="$pEnd"/>
          </xsl:call-template>
        </xsl:otherwise>
       </xsl:choose>
      </xsl:if>
     </xsl:template>
</xsl:stylesheet>

Lorsqu'elle est appliquée à un document XML (non utilisé), cette transformation produit le résultat souhaité - tous les nombres compris entre 1 et 1000000.

Vous pouvez utiliser/adapter cette transformation pour toute tâche devant "effectuer quelque chose N fois".

22
Dimitre Novatchev

Vérification très simple à l'intérieur de la boucle foreach

<xsl:if test="$maxItems > position()">
    do something
</xsl:if>

Basé sur Dimitre Novatchev's answer.

Exemple:

<xsl:variable name="maxItems" select="10" />
<xsl:variable name="sequence" select="any-sequence"/>

<xsl:for-each select="$sequence">

    <!-- Maybe sort first -->
    <xsl:sort select="@sort-by" order="descending" />

    <!-- where the magic happens -->
    <xsl:if test="$maxItems > position()">
        do something
    </xsl:if>
</xsl:for-each>
3
Aart den Braber

XSLT fonctionne à partir de modèles et vous aurez besoin d'un modèle pour exécuter cette boucle.

Vous devrez créer un modèle recevant les valeurs de début et de fin et, à l'intérieur, effectuer un calcul récursif des appels avec début + 1. Lorsque $ start est égal à $ end, vous renvoyez votre modèle, sans autre appel.

En pratique: http://www.ibm.com/developerworks/xml/library/x-tiploop/index.html

0
Rubens Farias