One of the old secrets of text processing used to be using multiple stages: a pipeline so that each stage did something clear and comprehensible. The programming language OmniMark actually built this notion in, first by having a three stage processor (text, SGML, ESIS) then by generalizing these into processes; in OmniMark they were all implemented as efficent co-routines or semi-co-routines.

But I only figured out how to do this in XSLT recently, multiple stages in a single script (not to be confused with multiple passes of the same data, which modes handle, nor with functions). Probably it is obvious to everyone else. It had never really clicked with me that you can store a tree of elements made from parsing the input data in a variable, then use another set of templates to process that, perhaps into another variable. It is not as flexible as OmnIMark still (no validation=no enforced unit test; no processing of unmarked-up text into marked-up text).

A typical strategy when converting from XML into some structured text format is to have three transformations:

  • first, convert the XML into ideal XML: resolve links as needed, remove extraneous elements and attributes, convert cases, generate headings and other things that need to be generated
  • second, convert that ideal XML into an XML-ized version of the output format
  • third, convert the output XML into the text format, delimiting and indenting as needed

I habitually did this using separate XSLT stages, using a shell script or bat file. But here is how to have all the three stages inside the same XSLT script: have variables for each stage. You can store static or dynamic XML in a variable and parse that:

<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text" indent="yes" />   

<xsl:variable name="data">
  <x><y><z/></y></x>
</xsl:variable>

<xsl:template match="/">
Here:
 <xsl:apply-templates select="$data/*" />   

</xsl:template>

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

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

<xsl:template match="z">
   z
   <xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

[CORRECTION: This next part is not right, unfortunately. See Kurt and David’s comments below instead.]

So in a three-stage process like the one above, the main template would look something like this:

<xsl:template match="/">

 <variable name="idealXML">
     <xsl:apply-templates mode="stage1"  />
 </variable>   

 <variable name="outputXML">
     <xsl:apply-templates mode="stage2"  select=" $idealXML/*" />
 </variable>   

     <xsl:apply-templates mode="stage3"  select=" $outputXML/*" /> 

</xsl:template>