I. This demonstrates how to perform multiple-pass XSLT 1.0 transformations with any XSLT 1.0 processor that supports the exslt node-set() extension function, including .NET XslCompiledTransform.
For other XSLT 1.0 processors one needs to replace ext:node-set()
by whatever they support, such as msxsl:node-set()
(with msxsl associated with the correct namespace) for MSXML.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common"
exclude-result-prefixes="ext xsl">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="node()"/>
</xsl:variable>
<xsl:apply-templates mode="pass2"
select="ext:node-set($vrtfPass1)/node()"/>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<one/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/one" mode="pass2" >
<xsl:call-template name="identity"/>
<two/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on this XML document:
<doc/>
the wanted result is produced:
<doc>
<one/>
<two/>
</doc>
II. At present XSLT 1.0 and XSLT 2.0 use XPath and this requires the whole XML document (representation) to be in RAM.
The Working Draft for XSLT 2.1 (recently renamed to 3.0) proposes a new, streaming feature, which, if this WD becomes an official recommendation, will make it possible for compliant XSLT 3.0 processors to implement streaming.
III. XslCompiledTransform of an XPathDocument
still holds the whole XML document representation in memory. The fact that an XPathDocument
provides forward-only iteration doesn't mean that XslCompiledTransform performs any streaming of the XML document.