2011-04-13 11 views
6

He buscado por todas partes para encontrar una solución a mi problema, pero acabo de recibir más preguntas ...Plantilla de llamada XSLT con QName dinámico?

considerar el siguiente código XML:

<dynamicStuff> 
     <dyn id="name1">...</dyn> 
     <dyn id="name2">...</dyn> 
     <dyn id="name3">...</dyn> 
     <dyn id="name4">...</dyn> 
</dynamicStuff> 

y supongamos que el que tengo un archivo XSLT de la siguiente :

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

    <xsl:template name="name1">  
     ... 
    </xsl:template> 

    <xsl:template name="name2">  
     ... 
    </xsl:template> 

    <xsl:template name="name3">  
     ... 
    </xsl:template> 

    <xsl:template name="name4">  
     ... 
    </xsl:template> 

</xsl:stylesheet> 

Lo que quiero hacer es a partir de un archivo XSLT SEGUNDO dinámicamente determinar qué plantilla para llamar con algo como esto:

<xsl:variable name="templateName"> 
    <xsl:value-of select="dyn/@id"/> 
</xsl:variable> 

<xsl:call-template name="$templateName"/> 

lamentablemente no su trabajo, créeme cuando digo que he probado un montón de cosas diferentes, aunque suene tan simple que no funciona bien ...

Me estoy perdiendo algo?

Editar:

he hecho con éxito la siguiente:

<xsl:template name="staticName"> 
    <xsl:param name="id" /> 

    <xsl:if test="$id = 'name1'">....</xsl:if> 
    <xsl:if test="$id = 'name2'">....</xsl:if> 
    ... 
</xsl:template> 

Llamada de esta manera:

<xsl:call-template name="staticName"> 
    <xsl:with-param name="id" select="@id"/> 
</xsl:call-template> 

es necesario decir lo inconveniente que esto es ... en primer todo mi código estará ligado a ese Nombre estático (imagine que necesito hacer esta llamada en una docena de archivos) ... segundo tendré un grupo de cont (no) relacionado ent dentro de la misma plantilla cuando podría ser más separados ... una pesadilla para actualizar el equipo uu

Hace lo que quiero, pero no de la manera que necesito ...

Gracias de antemano por cualquier luz ¡en este asunto!

Respuesta

6

De http://www.w3.org/TR/xslt#named-templates

El valor del atributo de name es una QName, que se expande como se describe en [2.4 Qualified Names].

Significa que no es ni una expresión ni un AVT.

explícitos xsl:call-template instrucciones son bien sea por instrucciones de lógica o de coincidencia de patrones como:

<xsl:template match="dyn[@id='name1']" mode="dynamic"> 
<xsl:call-template name="name1"/> 
</xsl:template> 

Otro enfoque es nombrado referencias plantilla ...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="vTemplate" select="document('')/*/xsl:template"/> 
    <xsl:template match="dyn"> 
     <xsl:apply-templates select="$vTemplate[@name = current()/@id]"/> 
    </xsl:template> 
    <xsl:template match="xsl:template[@name='name1']" 
        name="name1"> one </xsl:template> 
    <xsl:template match="xsl:template[@name='name2']" 
        name="name2"> two </xsl:template> 
    <xsl:template match="xsl:template[@name='name3']" 
        name="name3"> three </xsl:template> 
    <xsl:template match="xsl:template[@name='name4']" 
        name="name4"> four </xsl:template> 
</xsl:stylesheet> 

Salida:

one two three four 


Nota: Debido a que esta técnica utiliza document('') para procesar la XSLT en lugar del archivo XML original, el documento original que se está procesando no está disponible en las plantillas con nombre. Sin embargo, puede pasar explícitamente current() como parámetro para las plantillas si es necesario:

<xsl:template match="dyn"> 
     <xsl:apply-templates select="$vTemplate[@name = current()/@id]"> 
      <xsl:with-param name="current" select="current()"/> 
     </xsl:apply-templates> 
    </xsl:template> 

Si es necesario, $current se puede utilizar para tener acceso al documento original:

<xsl:template match="xsl:template[@name='name1']" name="name1"> 
     <xsl:param name="current"/> 
     <xsl:value-of select="$current/@id"/> 
     <xsl:text> becomes one</xsl:text> 
    </xsl:template> 

Si es necesario, $current podría ser re- establecido como nodo actual usando for-each:

<xsl:template match="xsl:template[@name='name2']" name="name2"> 
    <xsl:param name="current"/> 
    <xsl:for-each select="$current"> 
      <xsl:value-of select="@id"/> 
      <xsl:text> becomes two</xsl:text> 
    </xsl:for-each> 
</xsl:template> 
1

Si solo tiene un número finito de plantillas posibles, ¿sería útil utilizar una construcción xsl if para seleccionar qué hacer en la plantilla maestra?

<xsl:if test="$templateName = 'name1'"> 
    <xsl:call-template name="name1"/> 
</xsl:if> 
+0

lamentablemente el número de posibles eventos no es pequeño ... aunque es finito. El gran problema es que no está agrupado todo en un solo archivo – Fawix

+0

Bueno, el problema es que no tengo un diseño fijo para el xml y puede aparecer en varias etiquetas diferentes (y varias xmls diferentes) solo con el ID para identificarlo, y mi XSLT es demasiado genérico para poder determinar el nombre ... Hasta ahora, lo mejor fue la solución utilizando parámetros. – Fawix

0

Lo que estamos tratando no es directamente posible, pero ¿por qué no simplemente partido en el valor del atributo id en el primer lugar? Si es absolutamente necesario el direccionamiento indirecto de la plantilla llamada, entonces llamaremos a partir de la plantilla que coincide por id (ver name4 abajo):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
     <t><xsl:apply-templates select="dynamicStuff/dyn"/></t> 
    </xsl:template> 
    <!-- match on attribute value --> 
    <xsl:template match="dyn[@id='name1']">name1</xsl:template> 
    <xsl:template match="dyn[@id='name2']">name2</xsl:template> 
    <xsl:template match="dyn[@id='name3']">name3</xsl:template> 
    <xsl:template match="dyn[@id='name4']"> 
     <xsl:call-template name="name4"/> 
    </xsl:template> 
    <!-- named templates --> 
    <xsl:template name="name1">name1</xsl:template> 
    <xsl:template name="name2">name2</xsl:template> 
    <xsl:template name="name3">name3</xsl:template> 
    <xsl:template name="name4">name4</xsl:template> 
</xsl:stylesheet> 

de entrada:

<dynamicStuff> 
    <dyn id="name1">...</dyn> 
    <dyn id="name2">...</dyn> 
    <dyn id="name3">...</dyn> 
    <dyn id="name4">...</dyn> 
</dynamicStuff> 

Salida:

<t>name1name2name3name4</t> 
+0

gracias por la respuesta! lamentablemente no tengo un solo XML y puede suceder en varias etiquetas diferentes (identificadas por el mismo ID), por lo que mapear con dyn [@ id = 'name1'] haría que mi código sea inmenso porque necesitaría asignar cada etiqueta en todos los archivos XML – Fawix

1

lo general, cuando alguien trata de hacer esto, significa que está ar e no es consciente de la potencia total de xsl: apply-templates. La forma de hacerlo despacho dinámico en XSLT es usar xsl: apply-templates. Por ejemplo, para el problema citado, escribir reglas plantilla como

<xsl:template match="dyn[@id='name1']">...</xsl:template> 
<xsl:template match="dyn[@id='name2']">...</xsl:template> 
<xsl:template match="dyn[@id='name3']">...</xsl:template> 

y luego usar <xsl:apply-templates select="dyn"/> para hacer el envío.

0

Si está utilizando el viejo Saxon-B o posterior Saxon-PE o Saxon-EE como el procesador XSLT, se puede utilizar una extensión sajón para lograr plantilla dinámica llama:

<xsl:variable name="templateName"> 
    <xsl:value-of select="dyn/@id"/> 
</xsl:variable> 

<saxon:call-template name="{$templateName}"/> 

No olvide declarar el saxon-Namespace en el elemento xsl-stylesheet:

<xsl:stylesheet xmlns:saxon="http://saxon.sf.net/" [...] > 
Cuestiones relacionadas