2008-11-28 5 views
2

J'ai un document XML avec plusieurs <person> éléments, dont chacun contient la <name> de la personne, et plusieurs <preferred-number> éléments à l'intérieur d'un élément de regroupement <preferred-numbers>.tri v1.0 XSLT pour obtenir la plus grande valeur, une nouvelle question

je l'ai déjà constaté que, pour obtenir le plus grand <preferred-number> que je dois faire un <xsl:apply-template> avec un <xsl:sort> intérieur puis prendre le premier élément, comme v1.0 XSLT n'a pas fn:max().

Mais je suppose que cela me donnerait la plus grande valeur de tous. Alors, comment pourrais-je organiser une feuille de style pour extraire <name> de chaque personne avec leur plus grand <preferred-number>?

+0

Dayron, voir ma réponse contenant deux solutions différentes à votre problème. –

Répondre

0

Quand il s'agit de trier des choses dans XSLT 1.0, vous devez utiliser une approche légèrement détournée si je me souviens bien. Si vous ne l'avez pas déjà fait, vous voudrez peut-être regarder dans Muenchian grouping pour vous donner quelques idées pour commencer. J'ai trouvé que this site était une ressource très utile.

2

On peut utiliser le modèle "maximum" tel que fourni par FXSL -- the Functional Programming Library for XSLT. FXSL est entièrement écrit en XSLT lui-même.

Voici un exemple d'utilisation du modèle "maximum":

Lorsque cette transformation:

 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:maximum-own-compare="maximum-own-compare" 
xmlns:Mycompare="Mycompare" 
exclude-result-prefixes="xsl f Mycompare" 
> 
    <xsl:import href="maximum.xsl"/> 

    <xsl:output method="text"/> 

    <!-- This transformation must be applied to: 
     numList.xml 
    --> 

    <Mycompare:Mycompare/> 

    <xsl:template match="/"> 
     <xsl:variable name="vCMPFun" 
      select="document('')/*/Mycompare:*[1]"/> 

     <xsl:call-template name="maximum"> 
     <xsl:with-param name="pList" select="/*/*"/> 
     <xsl:with-param name="pCMPFun" select="$vCMPFun"/> 

     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="MyIsGreater" mode="f:FXSL" 
     match="Mycompare:*"> 
     <xsl:param name="arg1"/> 
     <xsl:param name="arg2"/> 

     <xsl:choose> 
      <xsl:when test="$arg1 > $arg2">1</xsl:when> 
      <xsl:otherwise>0</xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

est appliqué sur ce document XML:

 
<nums> 
    <num>01</num> 
    <num>02</num> 
    <num>03</num> 
    <num>04</num> 
    <num>05</num> 
    <num>06</num> 
    <num>07</num> 
    <num>08</num> 
    <num>09</num> 
    <num>10</num> 
</nums> 

le résultat recherché est obtenu .

 
10 

Notez que je peux passer n'importe quelle opération de "comparaison" nécessaire comme paramètre! Par exemple, si mon opération de comparaison renvoie 1 lorsque $ arg1 < $ arg2, la transformation ci-dessus produira "01" - le minimum de toutes les valeurs.

Maintenant, je vais montrer deux solutions pour le problème original.

Solution1 (à l'aide du modèle "maximum" de la FXSL):

 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:Mycompare="Mycompare" 
exclude-result-prefixes="xsl f Mycompare" 
> 
    <xsl:import href="maximum.xsl"/> 

    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <Mycompare:Mycompare/> 

     <xsl:variable name="vCMPFun" 
      select="document('')/*/Mycompare:*[1]"/> 

    <xsl:template match="/"> 
     <persons> 
     <xsl:apply-templates select="*/*"/> 
     </persons> 
    </xsl:template> 
    <xsl:template match="person"> 
    <person> 
     <xsl:call-template name="maximum"> 
     <xsl:with-param name="pList" select="*/*"/> 
     <xsl:with-param name="pCMPFun" select="$vCMPFun"/> 

     </xsl:call-template> 
    </person> 
    </xsl:template> 

    <xsl:template name="MyIsGreater" mode="f:FXSL" 
     match="Mycompare:*"> 
     <xsl:param name="arg1"/> 
     <xsl:param name="arg2"/> 

     <xsl:choose> 
      <xsl:when test="$arg1 > $arg2">1</xsl:when> 
      <xsl:otherwise>0</xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le document XML suivant:

 
<t> 
    <person> 
     <preferred-number> 
      <preferred-number>8</preferred-number> 
      <preferred-number>10</preferred-number> 
      <preferred-number>4</preferred-number> 
      <preferred-number>12</preferred-number></preferred-number> 
    </person> 
    <person> 
     <preferred-number> 
      <preferred-number>2</preferred-number> 
      <preferred-number>11</preferred-number> 
      <preferred-number>15</preferred-number> 
      <preferred-number>6</preferred-number></preferred-number> 
    </person> 
    <person> 
     <preferred-number> 
      <preferred-number>10</preferred-number> 
      <preferred-number>44</preferred-number> 
      <preferred-number>9</preferred-number></preferred-number> 
    </person> 
</t> 

le résultat recherché est produit:

 
<persons> 
    <person> 
     <preferred-number>12</preferred-number> 
    </person> 
    <person> 
     <preferred-number>15</preferred-number> 
    </person> 
    <person> 
     <preferred-number>44</preferred-number> 
    </person> 
</persons> 

Solution2 (en utilisant un modèle écrit à la main):

Lorsque cette transformation:

 
<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="/"> 
    <persons> 
     <xsl:apply-templates select="*/*"/> 
    </persons> 
    </xsl:template> 

    <xsl:template match="person"> 
    <person> 
     <xsl:call-template name="maximum"> 
     <xsl:with-param name="pList" select="*/*"/> 
     </xsl:call-template> 
    </person> 
    </xsl:template> 

    <xsl:template name="maximum"> 
     <xsl:param name="pList"/> 

     <xsl:choose> 
     <xsl:when test="not($pList)"> 
     -99999999999999999999 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:variable name="vLen" select="count($pList)"/> 

     <xsl:choose> 
      <xsl:when test="$vLen = 1"> 
      <xsl:value-of select="$pList[1]"/> 
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:variable name="vHalf" 
      select="floor($vLen div 2)"/> 

      <xsl:variable name="vMax1"> 
      <xsl:call-template name="maximum"> 
       <xsl:with-param name="pList" 
       select="$pList[not(position() > $vHalf)]"/> 
      </xsl:call-template> 
      </xsl:variable> 

      <xsl:variable name="vMax2"> 
      <xsl:call-template name="maximum"> 
       <xsl:with-param name="pList" 
       select="$pList[position() > $vHalf]"/> 
      </xsl:call-template> 
      </xsl:variable> 

      <xsl:value-of 
      select="$vMax1*($vMax1 > $vMax2) 
        + 
        $vMax2*($vMax2 >= $vMax1) 
      "/> 
      </xsl:otherwise> 
     </xsl:choose> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet>

est appliqué sur le même document XML, encore une fois le résultat correct est produit:

 
<persons> 
    <person>12</person> 
    <person>15</person> 
    <person>44</person> 
</persons> 
Questions connexes