0

I have an XSLT that looks like this atm:

<xsl:template match="Root">           
<xsl:for-each select="Worksheettype[@name='DubieuzeDebiteurenApp']">
  <xsl:for-each select="Types/Sub/*">        
    <xsl:for-each select="./*">
      <xsl:value-of select="ancestor::Worksheettype/@TypeId"/> ; <xsl:value-of select="local-name(parent::*)"/> ; <xsl:value-of select="local-name()"/>
      <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>        
  </xsl:for-each>
</xsl:for-each>

<xsl:for-each select="Worksheettype[@name='VoorzieningenApp']">
  <xsl:for-each select="Types/Sub/*">
    <xsl:for-each select="./*">
      <xsl:value-of select="ancestor::Worksheettype/@TypeId"/> ; <xsl:value-of select="local-name(parent::*)"/> ; <xsl:value-of select="local-name()"/>
      <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
  </xsl:for-each>
</xsl:for-each>


<xsl:for-each select="Worksheettype[@name='RisicoKapitaalApp']">
  <xsl:for-each select="Types/Sub/*">
    <xsl:for-each select="./*">
      <xsl:value-of select="ancestor::Worksheettype/@TypeId"/> ; <xsl:value-of select="local-name(parent::*)"/> ; <xsl:value-of select="local-name()"/>
      <xsl:text>&#xa;</xsl:text>
    </xsl:for-each>
  </xsl:for-each>
</xsl:for-each>
</xsl:template>

It works OK but as you can see I have 3 identical blocks of code but each with a different select parameter on the for-each statement.

I would like to create a variable where i could store the 3 select parameters and simple iterate through them so i could reduce my code to only 1 block.

I have tried creating a variable but it always fails...

Any help is much appreciated :)

Thanks!

2 Answers 2

1

You could use a named template here, and just pass in the worksheet name as a parameter

<xsl:template name="Worksheettype">
   <xsl:param name="typeName" />
   <xsl:for-each select="Worksheettype[@name=$typeName]"> 
        <!-- Remaining code -->
   </xsl:for-each>
</xsl:template>

Then you would call it like so

<xsl:call-template name="Worksheettype">
   <xsl:with-param name="typeName" select="'DubieuzeDebiteurenApp'" />
</xsl:call-template>

<xsl:call-template name="Worksheettype">
   <xsl:with-param name="typeName" select="'VoorzieningenApp'" />
</xsl:call-template>

<xsl:call-template name="Worksheettype">
   <xsl:with-param name="typeName" select="'RisicoKapitaalApp'" />
</xsl:call-template>

Another approach would be to use template matching. Firstly create a template that matches Worksheettype, like so

<xsl:template match="Worksheettype">
    <xsl:for-each select="Types/Sub/*">
        <!-- Remaining code -->
    </xsl:for-each>
</xsl:template>

Then you would apply the relevant templates for each of your attribute type

<xsl:apply-templates select="Worksheettype[@type='DubieuzeDebiteurenApp']" />

<xsl:apply-templates select="Worksheettype[@type='VoorzieningenApp']" />

<xsl:apply-templates select="Worksheettype[@type='RisicoKapitaalApp']" />

This approach is probably more in the spirit of XSLT, and would remove the use of one xsl:for-each.

Sign up to request clarification or add additional context in comments.

3 Comments

The apply-templates solution is the better one.
@Fbo, If you want to learn something (which I believe is the main goal of any member of SO), then listen to the advise of Michael Kay, and also the recommendation of TimC and also my own recommendation that using xsl:apply-templates is superior to xsl:call-template.
Thanks for the advice Dimitre! I will change my code so it uses apply instead of call!
1

Fbo, You haven't specified which version of XSLT you are on.

XSLT 2.0 Solution

If you can use XSLT 2.0, then by far the simplest solution is to use the XPATH comma (,) operator, which would look like this ...

<xsl:for-each select="Worksheettype[@name='DubieuzeDebiteurenApp'],
                      Worksheettype[@name='VoorzieningenApp'],
                      Worksheettype[@name='RisicoKapitaalApp']">
  <xsl:for-each select="Types/Sub/*">        
    <xsl:for-each select="./*">
      ... banana banana banana etc.       
  </xsl:for-each>
</xsl:for-each>

The comma operator preserves the displayed iteration order (DubieuzeDebiteurenApp before VoorzieningenApp).

Conditional XSLT 1.0 solution

If it so happens that you don't care about iteration order (DubieuzeDebiteurenApp before VoorzieningenApp), or the order in your question is already in document order, then the simplest solution in XSLT 1.0 will be like this.

<xsl:for-each select="Worksheettype[ (@name='DubieuzeDebiteurenApp') or
                                     (@name='VoorzieningenApp')
                                     (@name='RisicoKapitaalApp')]">

... or equivalently in XSLT 2.0 ...

<xsl:for-each select="Worksheettype[ @name in
    ('DubieuzeDebiteurenApp','VoorzieningenApp','RisicoKapitaalApp')]">

Fallback XSLT 1.0 Solution

If you are stuck with XSLT 1.0, and the aforementioned special conditions do not apply, then use a template, named or otherwise, and 3 xsl:apply-templates as Tim C's solution. (Congrats to Tim for first correct post).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.