2010-04-07 8 views
8

J'ai une situation où la boucle par une nodeset triée et appliquer un modèle sur chacun des noeuds:Tri un nodeset avant de passer à xsl: for-each

<div id="contractscontainer"> 
    <xsl:for-each select="document"> 
    <xsl:sort select="content[@name='ClientName']/text()" /> 
    <xsl:apply-templates select="." mode="client-contract" /> 
    </xsl:for-each> 
</div> 

Je veux faire quelque chose de spécial avec le " d'abord "5 nœuds dans le nœud défini et rendu l'élément imbriqué. Le problème est qu'ils doivent être dans le même ordre que s'ils étaient triés (car ils sont dans la boucle).

J'avais prévu de le faire en utilisant deux éléments xsl:for-each, chacun avec les bons nœuds sélectionnés dans l'ensemble. Je ne peux pas le faire, cependant, parce qu'ils ont besoin d'être triés avant je peux sélectionner le « premier » 5.

Exemple:

<div id="contractscontainer"> 
    <div class="first-five"> 
    <xsl:for-each select="document[position() < 6]"> 
     <xsl:sort select="content[@name='ClientName']/text()" /> 
     <xsl:apply-templates select="." mode="client-contract" /> 
    </xsl:for-each> 
    </div> 
    <div class="rest-of-them"> 
    <xsl:for-each select="document[position() > 5]"> 
     <xsl:sort select="content[@name='ClientName']/text()" /> 
     <xsl:apply-templates select="." mode="client-contract" /> 
    </xsl:for-each> 
    </div> 
</div> 

Je ne pense pas que cela va fonctionner parce que je Sélectionne les noeuds par position avant en les triant, mais je ne peux pas utiliser xsl:sort en dehors du xsl:for-each.

Est-ce que je m'approche de cette façon?

Modifier: Ma solution actuelle est de les trier et stocker le tri défini dans une autre variable:

<xsl:variable name="sorted-docs"> 
    <xsl:for-each select="document"> 
    <xsl:sort select="content[@name='ClientName']/text()" /> 
    <xsl:copy-of select="." /> 
    </xsl:for-each> 
</xsl:variable> 

Il fonctionne, mais est-il une meilleure façon?

+0

Bonne question (+1). Votre solution actuelle n'est pas mauvaise, mais la variable xsl: avec les éléments triés est de type RTF et vous devez utiliser la fonction d'extension xxx: node-set() dans XSLT 1.0. Voir ma solution comment faire ceci sans avoir besoin de fonctions d'extension. –

+0

Oui, j'ai fini par faire exactement cela: en utilisant exsl: node-set(). Merci pour votre solution! –

Répondre

14

Voici une façon de le faire dans XSLT 1.0 sans qu'il soit nécessaire d'utiliser la fonction d'extension xxx:node-set():

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/*"> 
    <html> 
    <div class="first-five"> 
    <xsl:apply-templates select="num"> 
     <xsl:sort select="." data-type="number"/> 
     <xsl:with-param name="pStart" select="1"/> 
     <xsl:with-param name="pEnd" select="5"/> 
    </xsl:apply-templates> 
    </div> 
    <div class="rest-of-them"> 
    <xsl:apply-templates select="num"> 
     <xsl:sort select="." data-type="number"/> 
     <xsl:with-param name="pStart" select="6"/> 
    </xsl:apply-templates> 
    </div> 
    </html> 
</xsl:template> 

<xsl:template match="num"> 
    <xsl:param name="pStart"/> 
    <xsl:param name="pEnd" select="999999999999"/> 

    <xsl:if test="position() >= $pStart 
       and 
       not(position() > $pEnd)"> 
    <p><xsl:value-of select="."/></p> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

Lorsque la transformation ci-dessus est appliquée sur ce document XML simple:

<nums> 
    <num>5</num> 
    <num>3</num> 
    <num>6</num> 
    <num>8</num> 
    <num>4</num> 
    <num>1</num> 
    <num>9</num> 
    <num>2</num> 
    <num>7</num> 
    <num>10</num> 
</nums> 

le résultat désiré est produit:

<html> 
    <div class="first-five"> 
     <p>1</p> 
     <p>2</p> 
     <p>3</p> 
     <p>4</p> 
     <p>5</p> 
    </div> 
    <div class="rest-of-them"> 
     <p>6</p> 
     <p>7</p> 
     <p>8</p> 
     <p>9</p> 
     <p>10</p> 
    </div> 
</html> 
+0

Résolu mon problème, merci –

Questions connexes