¿Cuáles son las diferencias entre 'call-template' y 'apply-templates' en XSL?

119

Soy nuevo en XSLT, así que estoy un poco confundido acerca de las dos etiquetas,

<xsl:apply-templates name="nodes">

y

<xsl:call-template select="nodes"> 

Entonces, ¿puede enumerar la diferencia entre ellos?

Venkat
fuente

Respuestas:

167

<xsl:call-template> es un equivalente cercano a llamar a una función en un lenguaje de programación tradicional.

Puede definir funciones en XSLT, como esta sencilla que genera una cadena.

<xsl:template name="dosomething">
  <xsl:text>A function that does something</xsl:text>
</xsl:template>

Esta función se puede llamar a través de <xsl:call-template name="dosomething">.

<xsl:apply-templates>es un poco diferente y en él está el poder real de XSLT: toma cualquier número de nodos XML (lo que sea que defina en el selectatributo), los itera ( esto es importante: ¡las plantillas de aplicación funcionan como un bucle! ) y encuentra plantillas coincidentes para ellos:

<!-- sample XML snippet -->
<xml>
  <foo /><bar /><baz />
</xml>

<!-- sample XSLT snippet -->
<xsl:template match="xml">
  <xsl:apply-templates select="*" /> <!-- three nodes selected here -->
</xsl:template>

<xsl:template match="foo"> <!-- will be called once -->
  <xsl:text>foo element encountered</xsl:text>
</xsl:template>

<xsl:template match="*"> <!-- will be called twice -->
  <xsl:text>other element countered</xsl:text>
</xsl:template>

De esta manera, cede un poco de control al procesador XSLT; no es usted quien decide a dónde va el flujo del programa, sino que el procesador lo hace al encontrar la coincidencia más adecuada para el nodo que está procesando actualmente.

Si varias plantillas pueden coincidir con un nodo, gana la que tenga la expresión de coincidencia más específica. Si existe más de una plantilla coincidente con la misma especificidad, la última declarada gana.

Puede concentrarse más en desarrollar plantillas y necesitar menos tiempo para hacer "plomería". Sus programas se volverán más potentes y modularizados, menos anidados y más rápidos (ya que los procesadores XSLT están optimizados para la coincidencia de plantillas).

Un concepto para entender con XSLT es el de "nodo actual". Con <xsl:apply-templates>el nodo actual avanza con cada iteración, mientras <xsl:call-template>que no cambia el nodo actual. Es decir, .dentro de una plantilla llamada se refiere al mismo nodo que .en la plantilla de llamada. Este no es el caso de las plantillas de aplicación.

Ésta es la diferencia básica. Hay algunos otros aspectos de las plantillas que afectan su comportamiento: sus modey priority, el hecho de que las plantillas pueden tener una namey una match. También influye si la plantilla se ha importado ( <xsl:import>) o no. Estos son usos avanzados y puedes lidiar con ellos cuando llegues allí.

Tomalak
fuente
5
@Tomalak: ¡Buena respuesta! Sin embargo, la declaración: "xsl: apply-templates es un bucle" no es correcta. No hay ninguna indicación en ninguna especificación oficial del W3C que <xsl:apply-templates>deba implementarse como un bucle; por el contrario, puede implementarse en paralelo, porque las diferentes aplicaciones en los diferentes nodos de la lista de nodos son absolutamente independientes entre sí.
Dimitre Novatchev
8
@Dimitre: Lo que quise decir: desde la perspectiva del usuario final, se <xsl:apply-templates>comporta como un bucle. Las diferencias de implementación en el extremo del procesador XSLT no me afectarán como programador XSLT, el resultado es absolutamente el mismo para implementaciones paralelas e iterativas por igual. Pero para un novato de XSLT con un trasfondo imperativo, es útil visualizarlo <xsl:apply-templates>como una especie de bucle para cada ciclo, incluso si, técnicamente, no lo es.
Tomalak
@Tomalak: Si bien esto puede ser útil para los programadores XSLT novatos, creo que a menudo es engañoso para ellos, ya que piensan que pueden reutilizar la información de estado acumulada en la "ejecución del ciclo".
Dimitre Novatchev
@Tomalak: Debido a estos hechos, creo que sería apropiado modificar "xsl: apply-templates es un bucle" con algo como: "xsl: apply-templates es como un bucle"
Dimitre Novatchev
@Tomalak: Loop es iteración, algo apply-templatesy las call-templateinstrucciones no son para. Son el mecanismo de recursividad en XSLT. Y como ha respondido Dimitre, aplicar plantillas es el polimorfismo o mecanismo impulsado por datos.
15

Para agregar a la buena respuesta de @Tomalak:

Aquí hay algunas diferencias importantes no mencionadas :

  1. xsl:apply-templateses mucho más rico y profundo que xsl:call-templatese incluso de xsl:for-each, simplemente porque no sabemos qué código se aplicará en los nodos de la selección; en el caso general, este código será diferente para los diferentes nodos de la lista de nodos.

  2. El código que se aplicará puede ser escrito mucho después de que se haya escrito la xsl:apply templates y por personas que no conozcan al autor original.

La implementación de funciones de orden superior (HOF) de la biblioteca FXSL en XSLT no sería posible si XSLT no tuviera la <xsl:apply-templates>instrucción.

Resumen : Las plantillas y la <xsl:apply-templates>instrucción muestran cómo XSLT implementa y trata el polimorfismo.

Referencia : Vea todo este hilo: http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200411/msg00546.html

Dimitre Novatchev
fuente
8

xsl:apply-templatesse utiliza normalmente (pero no necesariamente) para procesar todos o un subconjunto de los hijos del nodo actual con todas las plantillas aplicables. Esto admite la recursividad de la aplicación XSLT que coincide con la (posible) recursividad del XML procesado.

xsl:call-templatepor otro lado, se parece mucho más a una llamada de función normal. Ejecuta exactamente una plantilla (con nombre), generalmente con uno o más parámetros.

Entonces lo uso xsl:apply-templatessi quiero interceptar el procesamiento de un nodo interesante y (generalmente) inyectar algo en el flujo de salida. Un ejemplo típico (simplificado) sería

<xsl:template match="foo">
  <bar>
    <xsl:apply-templates/>
  </bar>
</xsl:template>

mientras que con xsl:call-templatenormalmente resuelvo problemas como agregar el texto de algunos subnodos juntos, transformar conjuntos de nodos seleccionados en texto u otros conjuntos de nodos y cosas por el estilo, cualquier cosa para la que escribiría una función especializada y reutilizable.

Editar:

Como comentario adicional al texto específico de su pregunta:

<xsl:call-template name="nodes"/> 

Esto llama a una plantilla que se llama 'nodos':

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

Esta es una semántica diferente a:

<xsl:apply-templates select="nodes"/>

... que aplica todas las plantillas a todos los hijos de su nodo XML actual cuyo nombre es 'nodos'.

TToni
fuente
2

De hecho, la funcionalidad es similar (aparte de la semántica de llamada, donde se call-templaterequiere un nameatributo y una plantilla de nombres correspondiente).

Sin embargo, el analizador no se ejecutará de la misma forma.

Desde MSDN :

A diferencia <xsl:apply-templates>, <xsl:call-template>no cambia el nodo actual ni la lista de nodos actual.

Oded
fuente