2009-10-11 19 views
6

Me gustaría utilizar el valor de un parámetro xslt en una expresión xpath. Específicamente, como parte de una llamada not() en una expresión <xsl:if.¿Es posible utilizar una expresión Dynamic xPath en una hoja de estilo xslt?

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <!-- my_param contains a string '/foo/bar', passed in from ant --> 
    <!-- the 'no' is just a default value --> 
    <xsl:param name="my_param">no</xsl:param> 
    <xsl:variable name="var_myparam" select="$my_param" /> 
    <!-- ... --> 

    <!-- this works --> 
    <xsl:if test="not(/foo/bar)" /> <!-- expression returns boolean true --> 
     <!-- ... --> 
    </xsl:if> 

    <!-- I can't figure out how to do this the right way --> 
    <!-- None of these appear to work --> 
    <xsl:if test="not($var_myparam)" /> <!-- expression returns boolean false --> 
     <!-- ... --> 
    </xsl:if>  
    <xsl:if test="not({$var_myparam})" /> <!-- complains Required attribute 'test' is missing --> 
     <!-- ... --> 
    </xsl:if>  
    <xsl:if test="not({$myparam})" /> <!-- complains Required attribute 'test' is missing --> 
     <!-- ... --> 
    </xsl:if>  
    <xsl:if test="not($myparam)" />  <!-- expression returns boolean false --> 
     <!-- ... --> 
    </xsl:if>  

</xsl:transform> 

Estoy un poco claro en lo que la sintaxis correcta es para crear una expresión XPath dinámica en una hoja de estilo XSLT. También estoy un poco confuso sobre la diferencia entre un parámetro, una variable y cómo la expansión de ambos funciona. Por ejemplo, con parámetros, sé que a veces necesito los corchetes, y a veces no.

<!-- when creating an element, it seems I need brackets --> 
<xsl:element name="{$my_param}" /> 

<!-- when selecting an element value for the output stream, no brackets are needed --> 
<xsl:value-of select="$my_param"/> 

Cualquier ayuda general/específica sería muy apreciada.

+1

Véase también http://stackoverflow.com/questions/4630023/dynamic-xpath-in-xslt – Vadzim

Respuesta

5

Echa un vistazo http://www.exslt.org/. Mire específicamente el módulo dinámico: evaluar.

+0

¿Es esto posible con XSLT? Parece que EXSLT es una extensión que no está garantizada para ser parte del analizador en la máquina de un usuario (estoy tratando de escribir código portátil). ¿Es eso correcto? –

+0

No creo que sea posible con XSLT "fuera de la caja". El valor del parámetro se evaluará como una cadena, en lugar de un conjunto de nodos. Michael Kay respondió una pregunta similar hace unos años y recomendó usar la función de evaluación() como una solución. http://www.biglist.com/lists/xsl-list/archives/200406/msg00006.html –

+1

Michael Kay? ¿Qué sabe él al respecto? Parece que es EXSLT o nada, lo que significa que eres SOL a menos que uses uno de los analizadores bendecidos. –

3

Pruebe alguna variación de esto:

<xsl:if test="not($var_myparam = 'no'))"> 
</xsl:if> 

El problema está en cómo evalúa XPath booleanos. Cualquier cadena no vacía evaluará a verdadero en XPath. Consulte este write-up about xpath booleans.

En cuanto a sus otras preguntas ... Las variables y los parámetros actúan igual entre ellos en las expresiones XPath. Ambos se referencian con el formulario $ var.

Para cualquier atributo XSLT llamado "select", no necesita los corchetes. Los corchetes se utilizan en lo que se denominan "plantillas de valores de atributo". Se utilizan cuando XSLT está a la espera de una cadena, por ejemplo:

<xsl:template match="name-a"> 
    <xsl:variable name="old-name" select="name(.)" /> 
    <name-b old-name="{$old-name}" new-attribute="hello" /> 
</xsl:template> 

El XSLT spec talks about AVTs, y lo mismo ocurre this page.

+0

Información útil, gracias. Ligera mala comunicación por mi parte sin embargo. El parámetro que se está pasando es una cadena en la forma '/ foo/bar'. La cadena 'no' es solo un valor predeterminado. En el punto de mi declaración if, tengo '/ foo/bar' en un parámetro. Quiero usar esa cadena como una expresión xpath para verificar. ¿Es eso posible? –

+0

Hmm, en ese caso tendrá que usar una función de extensión, según la discusión en la respuesta de CNutt. saxon: eval() es una opción: http://www.saxonica.com/documentation/extensions/functions/evaluate.html –

4

XSLT no es compatible con la evaluación dinámica de XPath; es por eso que necesita utilizar una función de extensión como EXSLT evaluate para hacerlo.

Si no desea utilizar las funciones de extensión (y existen buenas razones para no hacerlo), otra posibilidad es consultar el DOM del documento de entrada antes de ejecutar la transformación y pasar el conjunto de nodos a la transformación como parámetro.

Editar

Sobre esas llaves: Esas son las plantillas de atributos de valor (AVTS). Estos son semánticamente equivalentes en una transformación XSLT:

<foo> 
    <xsl:attribute name="bar"> 
     <xsl:value-of select="XPathExpression"/> 
    </xsl:attribute> 
</foo> 

<foo bar="{XPathExpression}"/> 

La segunda es sólo un atajo para la primera.

Acerca de las variables y parámetros: sintácticamente, no hay diferencia entre una variable y un parámetro; en cualquier lugar que haga referencia a $foo en una expresión XPath funcionará igual si foo está definido por xsl:variable o xsl:param.

La diferencia entre los dos es cómo se llenan. Las variables se completan en la declaración xsl:variable. Los parámetros se declaran en una plantilla con nombre utilizando xsl:param, pero se completan con las llamadas a la plantilla con nombre, usando xsl:with-param, p. Ej.:

<xsl:call-template name="foo"> 
    <xsl:with-param name="bar" select="XPathExpression"/> 
</xsl:call-template> 

<xsl:template name="foo"> 
    <xsl:param name="bar"/> 
    ... 

La gran excepción a esta tocando la bocina es parámetros que son un niño de xsl:stylesheet. No hay forma de llenar esos parámetros dentro de la transformación; aquellos están poblados externamente, por cualquier mecanismo (específico del entorno) que invoque la transformación.

Un caso de uso bastante común compensa el hecho de que XSLT no tiene una función de fecha del sistema. Por lo que verá algo como:

<xsl:stylesheet ... 
    <xsl:param name="system-date"/> 
    ... 

y luego, cuando se invoca la transformación, algo como esto (en C#):

XsltArgumentList args = new XsltArgumentList(); 
args.AddParam("system-date", "", DateTime.Now.ToString("s")); 
xslt.Transform(input, args, result); 
+0

Sí, ese parece ser el caso. Era difícil encontrar a alguien que acabara de salir y decirlo (la mayoría de los artículos tienen un punto de vista "mira lo que puedes hacer", no un "mira lo que no puedes"). Con respecto a tu sugerencia, ¿qué herramientas dejarías? pasas un conjunto de nodos en un documento xslt como parámetro para la transformación? No creo que sea posible con hormiga, y me gustaría ver la semántica de las herramientas que sí lo soportan. –

+0

Cómo pasar un parámetro a una transformación funciona depende del procesador XSLT que esté usando. Por ejemplo, en C# usaría 'XmlNode.Select()' para construir un conjunto de nodos (es decir 'XmlNodeList'). Luego crearía un 'XmlArgumentList' objeto, rellene con el conjunto de nodos, y pasarlo a' XslCompiledTransform.Transform() '. Si está utilizando una herramienta que no le da acceso programático al DOM del documento de entrada, esa avenida probablemente abierto para ti. –

+0

¿Alguien sabe si hay una manera de pasar los nodos del argumento en Java con el XSLT incorporado? – Stroboskop

Cuestiones relacionadas