3

I'm doing some very complex XSLT 1.0 transformation (currently using 8 XSLT passes). I want to combine this 8 passes without merging them in one file (this would be too complex). My solution would be using xsl:include and exsl:node-set to merge the passes and store temporary results in variables.

But I have one problem: My transformation passes copies most of the nodes and modifying only certain aspects. Therefore I need to process the same nodes in every pass, but with different xsl:template! But how do I do that? How to tell that after the first pass I want to apply templates from other XSLT stylesheet?

Very simplified example what I'm currently doing (2 XSLT passes):

Source:

<h>something here</h>

After XSLT pass 1:

<h someattribute="1">something here</h>

After XSLT pass 2:

<h someattribute="1" somemoreattribute="2">something here, and even more</h>

My current approach is to call the XSLT processor twice and saving the results temporary on disk:

xsltproc stylesheet1.xsl input.xml >temp.xml
xsltproc stylesheet2.xsl temp.xml >finalresult.xml
therealmarv
  • 3,692
  • 4
  • 24
  • 42
  • 1
    +1 for good question. See this [answer](http://stackoverflow.com/questions/6720009/multiple-xslt-files-to-single-xslt-file-for-2-different-xml-files/6720353#6720353) and @Jukka's answer. – Emiliano Poggi Jul 21 '11 at 21:09

2 Answers2

2

One possible solution would be to change each of the stylesheets to use a distinct mode. Then you could import them all to your master stylesheet and do multiple passes by applying templates using each mode in turn:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                extension-element-prefixes="exsl"
                version="1.0">

  <xsl:import href="stylesheet1.xsl"/> <!-- assuming mode="stylesheet1" -->
  <xsl:import href="stylesheet2.xsl"/> <!-- assuming mode="stylesheet2" -->
  <xsl:import href="stylesheet3.xsl"/> <!-- assuming mode="stylesheet3" -->

  <xsl:template match="/">
    <xsl:variable name="temp1">
      <xsl:apply-templates select="." mode="stylesheet1"/>
    </xsl:variable>
    <xsl:variable name="temp2">
      <xsl:apply-templates mode="stylesheet2" select="exsl:node-set($temp1)"/>
    </xsl:variable>
    <xsl:apply-templates mode="stylesheet3" select="exsl:node-set($temp2)"/>
  </xsl:template>

</xsl:stylesheet>

The downside is that you need to modify the original stylesheets, adding appropriate mode attributes to each xsl:templateand xsl:apply-templates. You can still make the stylesheets also work independently by adding an extra template like this in each of them:

<xsl:template match="/">
  <xsl:apply-templates select="." mode="stylesheet1"/>
</xsl:template>
Jukka Matilainen
  • 9,608
  • 1
  • 25
  • 19
  • Great answer Jukka. Rewriting the XSLT and adding the mode is OK for me. Thank you for writing so much. I learned something new about XSLT. – therealmarv Jul 21 '11 at 23:23
  • Edited the answer, fixing the XSLT by adding `select="."` to `xsl:apply-templates` in two places, in order to make the stylesheet appropriately apply templates to the root node too. – Jukka Matilainen Jul 22 '11 at 05:13
0

Why not use

<xsl:param name="iteration"/>

And pass the iteration number to the stylesheet? You can then use it like this

<xsl:if test="$iteration = 1">
  ...
</xsl:if>

...or in other contexts

You can set the parameter with

javax.xml.transform.Transformer.setParameter("iteration", 1);

Or with ant:

<xslt ...>
  <param name="iteration" expression="1"/>
</xslt>
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • When I use `xsl:param` I will have big `xsl:choose` constructs in my templates and only 1 XSLT which nobody will understand. There is a reason why I have 8 seperate XSLTs -> they are very complex and seperate them into 8 XSLT was the only option to keep them maintainable. – therealmarv Jul 21 '11 at 09:34