views:

132

answers:

3

Context: .NET Framework 3.5

I realize how I can perform a single XML transformation using XSLT, but didn't find any good examples on chaining XML transformations.

Input: - XML document as XPathDocument. - File paths to multiple XSL files.

Expected output: - preferably XPathDocument/IXPathNavigable, representing the XML with all transformations applied, one by one.

Example scenario:

input xml: <doc></doc>

xsl-1: .xsl that adds <one /> as a child of the doc element. xsl-2: .xsl that adds <two /> as a child of the doc element.

Expected result

<doc><one /><two /></doc>

Goals

Leverage the forward only nature of XPathDocument/IXPathNavigable or better. Avoid loading entire document in memory.

+2  A: 

Maybe something like the following (I have not tried to compile this):

XslCompiledTransform xsl1 = new XslCompiledTransform();
xsl1.Load("xsl1.xsl");

XslCompiledTransform xsl2 = new XslCompiledTransform();
xsl1.Load("xsl2.xsl");

using (Stream stream = new MemoryStream())
{
     using (XmlReader xmlReader1 = XmlReader.Create("source.xml"))
     {
          xsl1.Transform(xmlReader1, stream);
     }

     stream1.Position = 0;

     using (XmlReader xmlReader2 = XmlReader.Create(stream))
     {
         xsl2.Transform(xmlReader2, "output.xml");
     }
}

By using the xmlreader you will get the forward only you are looking for. I have just outpu the first result to a MemoryStream but you could do this to a temporary file.

For that extra little bit of performance you may want to look at pre compiling your xslt.

XSLT Compiler (xsltc.exe)

Bronumski
A: 

If you want to avoid loading the entire document tree into memory you might want to consider a different technology than XSLT.

There is an approach called Streaming Transformations for XML (STX), which does not require the construction of an in-memory tree. You might want to check out the STX project on SourceForge.

For an overview on streaming transformations I'd recommend the following article:

An Introduction to Streaming Transformations for XML

0xA3
Downvoter, care to explain? My answer might not be a direct answer to the OP's problem but it shows another way of achieving the goal of a stream based transformation. STX is not a "dead" technology, it is e.g. used by several frameworks such as Cocoon, and different from the planned streaming feature in XSLT it can already be used today (though it is a different technology and more limited than XSLT).
0xA3
A: 

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.

Dimitre Novatchev
+1, I don't understand why this is downvoted. The first point *may* go beyond the question, but still this answer is correct and very helpful.
0xA3
Generally helpful perhaps, in fact I could extrapolate that xslt myself for some current work, but it doesn't answer this question at all. It demonstrates how to combine multiple xslt's into one using pure xslt, not to chain them as they are using .NET. And given that the OP's using .NET 3.5, the current state of XSLT3 while interesting, is irrelevant. The OP had specific inputs and goals, and this answer doesn't even attempt to achieve them. I can see why it was downvoted, but it wasn't me who did, I didn't see the point.
Flynn1179
@Flynn1179: The answer clearly states that the desired goal cannot be achieved and gives a future prospect indicating that this is indeed a problem being addressed in an upcoming XSLT version. I don't see why you would downvote that (I wouldn't downvote just because the answer is 'sorry, you can't do that').
0xA3
@0xA3: Thank you for your correct understanding of my answer. In it I am providing to the best of my knowledge an alternative to the requesting transformation chaining -- in XSLT, and I am explaining why this cannot be done using XSLT technology today. I am also giving a perspective with the forthcoming XSLT 3.0 streaming. As for @Flynn1179 downvoting correct answers, he had been doing this before -- at least to my answers -- and this only reflects his specific level of understanding XSLT, and also his own personality.
Dimitre Novatchev
Oh, grow up, Dimitre. I've only ever downvoted one of your answers, and I would not have done so had it not been wrong. However, rather than correct your error, you deleted the answer to remove my comments (and the comments of the moderator who chided you for personal attacks after you called me a coward), and then reposted the same wrong answer. Since then I've stayed away from commenting/voting on your posts until today, and even here I commented that it was useful, and tried to offer an explanation of why someone might have downvoted it. You *seriously* need to lay off the personal attacks.
Flynn1179
@0xA3: Just to point out, I DIDN'T say I would downvote it, I merely tried to offer a possible explanation for why someone would. As a rule, I only downvote an answer that is clearly wrong.
Flynn1179