views:

746

answers:

3

I'd like to apply a template with different parameters based on the result of a conditional. Something like this:

<xsl:choose>
    <xsl:when test="@attribute1">
        <xsl:apply-templates select='.' mode='custom_template'>
            <xsl:with-param name="attribute_name" tunnel="yes">Attribute no. 1</xsl:with-param>
            <xsl:with-param name="attribute_value" tunnel="yes"><xsl:value-of select="@attribute1"/></xsl:with-param>
        </xsl:apply-templates>
    </xsl:when>
    <xsl:when test="@attribute2">
        <xsl:apply-templates select='.' mode='custom_template'>
            <xsl:with-param name="attribute_name" tunnel="yes">Attribute no. 2</xsl:with-param>
            <xsl:with-param name="attribute_value" tunnel="yes"><xsl:value-of select="@attribute1"/></xsl:with-param>
        </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>
        <xsl:apply-templates select='.' mode='custom_template'>
            <xsl:with-param name="attribute_name" tunnel="yes">Error</xsl:with-param>
            <xsl:with-param name="attribute_value" tunnel="yes">No matching attribute   </xsl:with-param>
            </xsl:apply-templates>
    </xsl:otherwise>
</xsl:choose>

First of all, I suspect that this could be resolved in a much, much better way. (I'm entirely new to XSLT, so please suggest improvements and forgive the bloated code.)

Now for the question: how could I've set the parameters based on this conditional, and still used them in an xsl:apply-templates? I've tried to wrap the entire xsl:choose with a xsl:apply-templates start-/end-tag, but that's apparently not legal. Any clues?

+2  A: 

Nothing wrong with your method, but you can also append your conditional into xsl:template match attribute. This will lead to just one xsl:apply-templates, but several xsl:template elements

Rubens Farias
Thanks Rubens, however I'm not entirely sure what you're aiming at... I'm still too inexperienced to follow you without any concrete examples.
conciliator
+2  A: 

An alternate method would be to put the xsl:choose statements within the xsl:param elements

<xsl:apply-templates select="." mode="custom_template">
   <xsl:with-param name="attribute_name" tunnel="yes">
      <xsl:choose>
         <xsl:when test="@attribute1">Attribute no. 1</xsl:when>
         <xsl:when test="@attribute2">Attribute no. 2</xsl:when>
         <xsl:otherwise>Error</xsl:otherwise>
      </xsl:choose>
   </xsl:with-param>
   <xsl:with-param name="attribute_value" tunnel="yes">
      <xsl:choose>
         <xsl:when test="@attribute1"><xsl:value-of select="@attribute1"/></xsl:when>
         <xsl:when test="@attribute2"><xsl:value-of select="@attribute1"/></xsl:when>
         <xsl:otherwise>No matching attribute </xsl:otherwise>
      </xsl:choose>
   </xsl:with-param>
</xsl:apply-templates>
Tim C
+1. Beat me to it. ;-)
Tomalak
Thanks, Tim C! That seems better.
conciliator
A: 

You can get rid of all that logic and the modes by extracting your conditions into predicates. You don't say what the name of the element you're dealing with is, but assuming it's called foo then something like this should suffice:

<xsl:template match="foo[@attribute1]">
    <!-- 
         do stuff for the case when attribute1 is present 
         (and does not evaluate to false) 
    -->
</xsl:template>

<xsl:template match="foo[@attribute2]">
    <!-- 
         do stuff for the case when attribute2 is present 
         (and does not evaluate to false)
    -->
</xsl:template>

<xsl:template match="foo">
    <!-- 
         do stuff for the general case  
         (when neither attribute1 nor attribute 2 are present) 
    -->
</xsl:template>
NickFitz