2010-01-26 27 views
5

¿Estoy en lo cierto al pensar que una declaración apply-templates debe coincidir con todas las plantillas que posiblemente podrían aplicarse para una selección?Comprensión de `apply-templates` matching

Por ejemplo, dada la siguiente fragmento xml:

<doc> 
    <foo bar="1" baz="2">boz</foo> 
</doc> 

y la siguiente hoja de estilo:

<xsl:template match="/"> 
    <xsl:apply-templates select="foo" mode="xyz" /> 
</xsl:template> 

<xsl:template mode="xyz" match="foo[bar='1']"> 
    abc 
</xsl:template> 

<xsl:template mode="xyz" match="foo[baz='2']"> 
    def 
</xsl:template> 

que sería de esperar que la salida sea:

abc 
def 

¿Es esto correcto ?

Respuesta

6

No, usted no consigue las dos salidas, como se seleccionará sólo una plantilla. Consulte this page para conocer las reglas sobre resolución de conflictos si hay varias plantillas posibles.

Después de corregir su hoja de estilo (de manera similar a como lo hizo Rubens, pero con los mismos modos), esto generalmente dará como resultado que se aplique la última plantilla en su archivo xslt, por lo que la salida será def. Esto se debe a que las dos plantillas tienen la misma prioridad y si el procesador xslt no se detiene con un error, el estándar requiere que aplique el último:

Es un error si esto deja más de una regla de plantilla coincidente . Un procesador XSLT puede señalar el error; si no indica el error, debe recuperarse eligiendo, de entre las reglas de plantilla coincidentes que quedan, la última que aparece en la hoja de estilo.

+0

+1, buena respuesta –

0

Si arregla ese código XSLT (usted tiene algunos problemas de filtro) y la ejecutó, debería ver:

def

¿Por qué? <xsl:apply-templates /> coincidirá con primera plantilla que satisfaga su condición de coincidencia. Si tiene dos plantillas, usted debe diferir de lo que mediante el uso de <xsl:apply-templates>mode atributo, o mediante el uso de <xsl:template>priority atributo:

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

    <xsl:template match="/doc"> 
     <xsl:apply-templates select="foo" mode="2" /> 
    </xsl:template> 

    <xsl:template mode="1" match="foo[@bar='1']"> 
     abc 
    </xsl:template> 

    <xsl:template mode="2" match="foo[@baz='2']"> 
     def 
    </xsl:template> 

</xsl:stylesheet> 
4

Si hicieron quieren sus plantillas a emparejar para ambos atributos, a continuación, sólo se necesita para ajustar el XPATH match para seleccionar el atributos y poner la relación de foo en el predicado; en lugar de tener dos plantillas en conflicto que coincidan en el elemento foo con la misma especificidad (que tienen la misma prioridad).

<?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" encoding="UTF-8"/> 

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

<!--When templates match on foo, apply templates for it's attributes --> 
<xsl:template match="foo"> 
    <xsl:apply-templates select="@*"/> 
</xsl:template> 

<!--Unique template match for the bar attribute --> 
<xsl:template match="@bar[parent::foo and .='1']"> 
    abc 
</xsl:template> 

<!--Unique template match for the baz attribute --> 
<xsl:template match="@baz[parent::foo and .='2']"> 
    def 
</xsl:template> 

</xsl:stylesheet> 
+0

Gracias, esto es lo que quería hacer. Lamentablemente, no puedo aceptar la respuesta, ya que no entra en el "por qué". ;) –