2012-04-27 14 views
6

Si supponga di avere variabili $a, $b, $c e $d che contengono tutti i numeri. Mi piacerebbe ottenere il valore più piccolo (il più grande). Il mio approccio tipico XSLT 1.0 a questo èCome selezionare il valore più piccolo da un gruppo di variabili?

<xsl:variable name="minimum"> 
    <xsl:for-each select="$a | $b | $c | $d"> 
    <xsl:sort 
     select="." 
     data-type="number" 
     order="ascending" /> 
    <xsl:if test="position()=1"><xsl:value-of select="." /></xsl:if> 
    </xsl:for-each> 
</xsl:variable> 

Tuttavia, la mia XSLT 1.0 processore lamenta con

runtime error: file stylesheet.xslt line 106 element for-each
The 'select' expression does not evaluate to a node set.

Come posso calcolare il minimo (massimo) dei valori dati?


Certo, avrei potuto usare una lunga serie di dichiarazioni <xsl:when> e visualizzate tutte le combinazioni, ma mi piacerebbe un po 'come una soluzione più piccola.

+0

Il problema principale, credo, è che i numeri non sono nodi. – cHao

+0

Penso che il problema principale sia che in XSLT 1.0, l'espressione in 'select' deve essere valutata su un set di nodi. (http://www.w3.org/TR/xslt#for-each) –

risposta

5

Se le variabili sono staticamente valori (non dinamico calcolato) definito, allora qualcosa quanto segue può essere fatto con XSLT 1.0:

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

<xsl:variable name="vA" select="3"/> 
<xsl:variable name="vB" select="1"/> 
<xsl:variable name="vC" select="9"/> 
<xsl:variable name="vD" select="5"/> 

<xsl:template match="/"> 
    <xsl:for-each select= 
     "document('')/*/xsl:variable 
     [contains('|vA|vB|vC|vD|', concat('|', @name, '|'))] 
      /@select 
     "> 
     <xsl:sort data-type="number" order="ascending"/> 

     <xsl:if test="position() = 1"> 
     Smallest: <xsl:value-of select="."/> 
     </xsl:if> 
     <xsl:if test="position() = last()"> 
     Largest: <xsl:value-of select="."/> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

Quando questa trasformazione viene applicato su qualsiasi documento XML (non usato), il voluto, risultato corretto viene prodotto:

Smallest: 1 
    Largest: 9 

II. Ora supponiamo che le variabili siano definite dinamicamente.

possiamo fare qualcosa di simile (ma hanno bisogno della funzione xxx:node-set() estensione):

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

<xsl:variable name="vA" select="number(/*/*[3])"/> 
<xsl:variable name="vB" select="number(/*/*[1])"/> 
<xsl:variable name="vC" select="number(/*/*[9])"/> 
<xsl:variable name="vD" select="number(/*/*[5])"/> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfStore"> 
     <num><xsl:value-of select="$vA"/></num> 
     <num><xsl:value-of select="$vB"/></num> 
     <num><xsl:value-of select="$vC"/></num> 
     <num><xsl:value-of select="$vD"/></num> 
    </xsl:variable> 

    <xsl:for-each select="ext:node-set($vrtfStore)/*"> 
     <xsl:sort data-type="number" order="ascending"/> 

     <xsl:if test="position() = 1"> 
     Smallest: <xsl:value-of select="."/> 
     </xsl:if> 
     <xsl:if test="position() = last()"> 
     Largest: <xsl:value-of select="."/> 
     </xsl:if> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

quando questa trasformazione è applicato sul seguente documento 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> 

la desiderato, viene prodotto il risultato corretto:

Smallest: 1 
    Largest: 9 
+0

Quindi il documento ('') punta a XSLT xml stesso? Dovrà ri-analizzarlo? Un altro scherzo di fantasia, comunque, grazie. +1 –

+0

@PavelVeller: Sì, questo è spesso usato se si desidera avere dati in linea nel foglio di stile XSLT stesso e non in un file separato. Sì, la ri-analisi viene eseguita al momento dell'esecuzione e ciò non è troppo efficiente. Potresti essere interessato a vedere anche la seconda parte della soluzione. –

+0

La seconda parte fa il trucco, grazie. Le mie variabili sono di per sé minimi di espressioni più complicate sull'albero di input, quindi sicuramente non statiche. – bitmask

1

Non ho mai avuto a che fare questo a 1.0 (io uso 2.0), ma si potrebbe fare questo:

<xsl:variable name="minimum"> 
    <xsl:choose> 
     <xsl:when test="$b > $a and $c > $a and $d > $a"><xsl:value-of select="$a"/></xsl:when> 
     <xsl:when test="$a > $b and $c > $b and $d > $b"><xsl:value-of select="$b"/></xsl:when> 
     <xsl:when test="$b > $c and $a > $c and $d > $c"><xsl:value-of select="$c"/></xsl:when> 
     <xsl:when test="$b > $d and $c > $d and $a > $d"><xsl:value-of select="$d"/></xsl:when> 
    </xsl:choose> 
    </xsl:variable> 

Ci deve essere un modo migliore però.

+0

Il mio modo di pensare esattamente. Come ho già detto, ho già questo come piano di emergenza.Ma non è bello, e certamente non scala. – bitmask

+0

@bitmask - Ho completamente perso l'ultimo paragrafo della tua domanda in cui hai detto che potevi fare questo. Spero che qualcuno (probabilmente @DimitreNovatchev) avrà una soluzione molto migliore. –

3

Questa soluzione XSLT 1.0 utilizza i modelli ricorsivi per analizzare un elenco delimitato di valori per restituire il valore min/max dall'elenco.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 

    <xsl:variable name="a" select="'3'"/> 
    <xsl:variable name="b" select="'1'"/> 
    <xsl:variable name="c" select="'9'"/> 
    <xsl:variable name="d" select="'5'"/> 

    <xsl:template match="/"> 
     <xsl:text>&#xa;Smallest: </xsl:text> 
     <xsl:call-template name="min"> 
      <xsl:with-param name="values" select="concat($a,',',$b,',',$c,',',$d)"/>  
     </xsl:call-template> 

     <xsl:text>&#xa;Largest: </xsl:text> 
     <xsl:call-template name="max"> 
      <xsl:with-param name="values" select="concat($a,',',$b,',',$c,',',$d)"/>  
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="min"> 
     <xsl:param name="values" /> 
     <xsl:param name="delimiter" select="','"/> 
     <xsl:param name="min"/> 

     <xsl:variable name="currentValue" > 
      <xsl:choose> 
       <xsl:when test="contains($values, $delimiter)"> 
        <xsl:value-of select="substring-before($values,$delimiter)"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="$values"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:variable> 

     <xsl:variable name="minimumValue"> 
      <xsl:choose> 
       <xsl:when test="$min and $min > $currentValue"> 
        <xsl:value-of select="$currentValue"/> 
       </xsl:when> 
       <xsl:when test="$min"> 
        <xsl:value-of select="$min"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="$currentValue" /> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:variable> 

     <xsl:choose> 
      <xsl:when test="substring-after($values,$delimiter)"> 
       <xsl:call-template name="min"> 
        <xsl:with-param name="min" select="$minimumValue" /> 
        <xsl:with-param name="values" select="substring-after($values,$delimiter)" /> 
        <xsl:with-param name="delimiter" select="$delimiter"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$minimumValue" /> 
      </xsl:otherwise> 
     </xsl:choose>     
    </xsl:template> 


    <xsl:template name="max"> 
     <xsl:param name="values" /> 
     <xsl:param name="delimiter" select="','"/> 
     <xsl:param name="max"/> 

     <xsl:variable name="currentValue" > 
      <xsl:choose> 
       <xsl:when test="contains($values, $delimiter)"> 
        <xsl:value-of select="substring-before($values,$delimiter)"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="$values"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:variable> 

     <xsl:variable name="maximumValue"> 
      <xsl:choose> 
       <xsl:when test="$max and $currentValue > $max"> 
        <xsl:value-of select="$currentValue"/> 
       </xsl:when> 
       <xsl:when test="$max"> 
        <xsl:value-of select="$max"/> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:value-of select="$currentValue" /> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:variable> 

     <xsl:choose> 
      <xsl:when test="substring-after($values,$delimiter)"> 
       <xsl:call-template name="max"> 
        <xsl:with-param name="max" select="$maximumValue" /> 
        <xsl:with-param name="values" select="substring-after($values,$delimiter)" /> 
        <xsl:with-param name="delimiter" select="$delimiter"/> 
       </xsl:call-template> 
      </xsl:when> 
      <xsl:otherwise> 
       <xsl:value-of select="$maximumValue" /> 
      </xsl:otherwise> 
     </xsl:choose>     
    </xsl:template> 
</xsl:stylesheet> 

Quando viene eseguito, produce il seguente output:

Smallest: 1 
Largest: 9 
Problemi correlati