2011-10-03 12 views
13

Tengo solo conocimientos básicos de XSLT, así que le pido disculpas si esto es básico o imposible.Cómo hacer una segunda transformación en la salida de una plantilla XSLT

Tengo una plantilla de paginador que se utiliza en todas partes del sitio que estoy viendo. Hay un error en el que una búsqueda en particular necesita tener un parámetro categoryId adjunto al href de los enlaces de la página. No puedo alterar la hoja de estilo del paginador o de lo contrario solo le agregaré un parámetro. Lo que me gustaría hacer es aplicar la plantilla como luego hacer una segunda transformación en función de su resultado. es posible? ¿Cómo van normalmente los demás a extender plantillas de biblioteca?

Hasta ahora he pensado en hacer una copia recursiva de la salida y aplicar una plantilla a los hrefs a medida que se procesan. La sintaxis de eso se me escapa un poco, sobre todo porque ni siquiera estoy seguro de que sea posible.


Editar - Entre la respuesta de Dabbler y el comentario de Michael Kay llegamos allí. Aquí está mi prueba completa.

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="http://exslt.org/common"> 
    <!-- note we require the extensions for this transform --> 

    <!--We call the template to be extended here and store the result in a variable--> 
    <xsl:variable name="output1"> 
      <xsl:call-template name="pass1"/> 
    </xsl:variable> 

    <!--The template to be extended--> 
    <xsl:template name="pass1"> 
      <a href="url?param1=junk">foo</a> 
    </xsl:template> 

    <!--the second pass. we lock this down to a mode so we can control when it is applied--> 
    <xsl:template match="a" mode="pass2"> 
      <xsl:variable name="href" select="concat(@href, '&amp;', 'catid', '=', 'stuff')"/> 
      <a href="{$href}"><xsl:value-of select="."/></a> 
    </xsl:template> 

    <xsl:template match="/"> 
      <html><head></head><body> 
        <!--the node-set extension function turns the first pass back into a node set--> 
        <xsl:apply-templates select="ext:node-set($output1)" mode="pass2"/> 
      </body></html> 
    </xsl:template> 

</xsl:stylesheet> 

Respuesta

8

Es posible en XSLT 2; puede almacenar datos en una variable y llamar a apply-templates sobre eso.

Ejemplo básico:

<xsl:variable name="MyVar"> 
    <xsl:element name="Elem"/> <!-- Or anything that creates some output --> 
</xsl:variable> 
<xsl:apply-templates select="$MyVar"/> 

Y en algún lugar de su hoja de estilo tiene una plantilla que coincide con Elem. También puede usar un modo separado para mantener una distinción clara entre las dos fases (construir la variable y procesarla), especialmente cuando ambas fases usan plantillas que coinciden con los mismos nodos.

+5

y se puede hacer lo mismo en XSLT 1.0 con cualquier procesador que ofrece la exsl: conjunto de nodos() extensión: basta con sustituir la selección en las apply-templates con select = "exsl: node-set ($ MyVar)". –

15

Aquí es un ejemplo completo de cómo el procesamiento multi-pass se puede hacer con XSLT 1.0:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="http://exslt.org/common"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

    <xsl:template match="node()|@*" mode="mPass2"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*" mode="mPass2"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfPass1Result"> 
    <xsl:apply-templates/> 
    </xsl:variable> 

    <xsl:apply-templates mode="mPass2" 
     select="ext:node-set($vrtfPass1Result)/*"/> 
</xsl:template> 

<xsl:template match="num/text()"> 
    <xsl:value-of select="2*."/> 
</xsl:template> 

<xsl:template match="/*" mode="mPass2"> 
    <xsl:copy> 
    <xsl:copy-of select="@*"/> 
    <xsl:apply-templates mode="mPass2"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="num/text()" mode="mPass2"> 
    <xsl:value-of select="3 + ."/> 
</xsl:template> 
</xsl:stylesheet> 

cuando se aplica esta transformación en el siguiente 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> 

el resultado deseado (cada num se multiplica por 2 y en la siguiente pasada 3 se añaden a cada num) se produce:

<nums> 
    <num>5</num> 
    <num>7</num> 
    <num>9</num> 
    <num>11</num> 
    <num>13</num> 
    <num>15</num> 
    <num>17</num> 
    <num>19</num> 
    <num>21</num> 
    <num>23</num> 
</nums> 
Cuestiones relacionadas