xslt - transformar - xsl if
construir la variable del conjunto de nodos desde el fragmento del árbol de resultados usando<xsl: choose> (2)
¿Es posible crear una variable de conjunto de nodos desde un rtf usando xsl:choose
(para usar en el motor MSXML)?
Tengo la siguiente construcción:
<xsl:choose>
<xsl:when test="function-available(''msxsl:node-set'')">
<xsl:variable name="colorList" select="msxsl:node-set($std:colorList)"/>
<xsl:for-each select="$colorList/color">
tr.testid<xsl:value-of select="@testid"/> {
color:<xsl:value-of select="."/>;
}
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="colorList" select="$std:colorList"/>
<xsl:for-each select="$colorList/color">
tr.testid<xsl:value-of select="@testid"/> {
color:<xsl:value-of select="."/>;
}
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
std:colorList
es el fragmento de árbol, por supuesto. Lo anterior funciona bien, y está bien porque el código es el mismo para las dos alternativas, pero no es tan grande.
Pero para fragmentos de código más grandes, me pregunto si es posible evitar la duplicación de código declarando primero la variable basada en el rtf, y luego realizar el código; algo como
<xsl:variable name="colorList">
<xsl:choose>
<xsl:when test="function-available(''msxsl:node-set'')">
<xsl:copy-of select="msxsl:node-set($std:colorList)"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$std:colorList"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:for-each select="$colorList/color">
tr.testid<xsl:value-of select="@testid"/> {
color:<xsl:value-of select="."/>;
}
</xsl:for-each>
Pero esto no funciona correctamente: MSXML se queja de que colorList
no es un conjunto de nodos, por lo que no se puede usar en xsl:for-each
.
XSL transformation failed due to following error:
Expression must evaluate to a node-set.
-->$colorList<--/color
Tenga en cuenta que en el ejemplo de trabajo, este error no ocurrió debido a "copiar" std:colorList
en la variable colorList
. Aparentemente es un error de análisis xsl, no uno de tiempo de ejecución.
¿Debo usar algo más que xsl:copy-of
? ¿O hay otra forma de lograr lo mismo?
En caso de que se pregunte, los contenidos de std:colorList
son los siguientes:
<std:colorList>
<color testid="111">#FF0000</color>
<color testid="999">#FFFF00</color>
</std:colorList>
Desafortunadamente en XSLT 1.0, cuando xsl: variable contiene instrucciones en lugar de un atributo de selección, el resultado siempre es un RTF. Por lo tanto, sus intentos cuidadosos de convertir el RTF en un conjunto de nodos no sirven para nada, porque se convierte directamente de nuevo.
Me temo que no hay una solución limpia (aparte de pasar a XSLT 2.0, por supuesto). Sugeriría estructurar el código así:
<xsl:choose>
<xsl:when test="function-available(''msxsl:node-set'')">
<xsl:apply-templates select="msxsl:node-set($std:colorList)/color" mode="z"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$std:colorList/color" mode="z"/>
</xsl:otherwise>
</xsl:choose>
<xsl:template match="color" mode="z">
tr.testid<xsl:value-of select="@testid"/> {
color:<xsl:value-of select="."/>;
}
</xsl:template>
Solo para el registro, agrego la solución final a continuación. Es ligeramente diferente de lo que Michael propuso, al agregar una copia del RTF a una variable antes de aplicar la plantilla.
Esto se debe a que, de lo contrario, MSXML sigue cometiendo errores durante el análisis xsl (aparentemente comprueba el valor de selección de plantillas de aplicación y concluye que no es correcto cuando se trata de un RTF en lugar de un conjunto de nodos. Y, como dijo Michael, el atributo xsl: variable select no solo eso: convertir un RTF a un conjunto de nodos.
<xsl:choose>
<xsl:when test="function-available(''msxsl:node-set'')">
<xsl:apply-templates select="msxsl:node-set($std:colorList)/color" mode="addTRclassToCSS"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="colorList" select="$std:colorList"/>
<xsl:apply-templates select="$colorList" mode="addTRclassToCSS"/>
</xsl:otherwise>
</xsl:choose>
<xsl:template match="color" mode="addTRclassToCSS">
tr.testid<xsl:value-of select="@testid"/> {
color:<xsl:value-of select="."/>;
}
</xsl:template>