Realización de una cadena de transformaciones se utiliza muy a menudo en aplicaciones XSLT, aunque haciendo esto enteramente en XSLT 1.0 requiere el uso de la función específica del proveedor xxx:node-set()
. En XSLT 2.0 no se necesita dicha extensión ya que el infame tipo de datos RTF se elimina allí.
Aquí es un ejemplo (demasiado simple para ser significativo, pero que ilustra completamente cómo se hace esto):
<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:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="/*/*"/>
</xsl:variable>
<xsl:variable name="vPass1"
select="ext:node-set($vrtfPass1)"/>
<xsl:apply-templates mode="pass2"
select="$vPass1/*"/>
</xsl:template>
<xsl:template match="num[. mod 2 = 1]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="num" mode="pass2">
<xsl:copy>
<xsl:value-of select=". *2"/>
</xsl:copy>
</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, correcto se produce:
<num>2</num>
<num>6</num>
<num>10</num>
<num>14</num>
<num>18</num>
Explicación:
En el primer paso el documento XML se transforma y el resultado se define como el valor de la variable $vrtfPass1
. Esto copia solo los elementos num
que tienen un valor impar (ni siquiera).
La variable $vrtfPass1
, siendo de tipo RTF, no es directamente utilizable para XPath expresiones por lo que la convierten en un árbol normal, utilizando el EXSLT (implementado por la mayoría de XSLT 1.0 procesadores) de función ext:node-set
y la definición de una variable - - $vPass1
cuyo valor es este árbol.
ahora realizamos la segunda transformación en nuestra cadena de transformaciones - en el resultado de la primera transformación, que se mantiene como el valor de la variable $vPass1
. Para no meterse con la plantilla de primer paso, especificamos que el nuevo procesamiento debe estar en un modo con nombre, llamado "pass2". En este modo, el valor de cualquier elemento num
se multiplica por dos.
XSLT 2.0 solución (no hay RTF):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vPass1" >
<xsl:apply-templates select="/*/*"/>
</xsl:variable>
<xsl:apply-templates mode="pass2"
select="$vPass1/*"/>
</xsl:template>
<xsl:template match="num[. mod 2 = 1]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="num" mode="pass2">
<xsl:copy>
<xsl:value-of select=". *2"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Buena pregunta, +1. Ver mi respuesta para una explicación y un ejemplo de código completo. :) –
Sí, es aceptado, pero no siempre es necesario. Si está utilizando Java, el Transformerfactory puede configurarse para barrer transformaciones sucesivas y evitar operaciones de análisis innecesarias. http://stackoverflow.com/questions/1312406/efficient-xslt-pipeline-in-java-or-redirecting-results-to-sources/1319774#1319774 –