Introducing XslCompiledTransform
This article is not finished. Please do not copy its content, make a link instead.
To improve XSLT execution performance in the .NET Framework version 2.0, the XslTransform
class has been replaced with a new XSLT 1.0 implementation: the XslCompiledTransform
class. XslCompiledTransform
compiles XSLT stylesheets to Microsoft Intermediate Language (MSIL) methods and then executes them. Execution time of the new processor is on average 4 times better than XslTransform
and matches the speed of MSXML, the native XML processor.
Although XslCompiledTransform
is designed to be as compatible with XslTransform
as possible, differences between the two classes nonetheless exist. The purpose of this document is to cover known differences between XslTransform
to XslCompiledTransform
and to simplify migration from the former to the latter.
Before we can talk about migration, it's worth briefly outlining how XslCompiledTransform
works.
When the Load
method is called, XslCompiledTransform
reads stylesheet modules from XmlReader
and creates an abstract syntax tree (AST) of the principal stylesheet module and all its imports and includes. It then compiles all script blocks to assemblies (one assembly per script namespace per script language). Finally it compiles the AST to a separate assembly.
Once the stylesheet is fully loaded, XslCompiledTransform
can transform the input document. Transformation of the input document to output involves the following steps:
- Parsing the input document and building an in-memory XML tree representation for it.
- Transforming the input XML tree to the output tree.
- Serialization of the output tree.
To load the cache, XslCompiledTransform
uses XmlReader
to read the input document. At this time, XslCompiledTransform
applies whitespace stripping rules.
If the input document was specified as a Uniform Resource Identifier (URI) string, XslCompiledTransform
creates an XmlReader
to read the XML document from that URI using default XmlReaderSettings
, but allowing Document Type Definition (DTD):
XmlReaderSettings rs = new XmlReaderSettings();
rs.ProhibitDtd = false;
XmlReader.Create(inputUri, rs);
If the input document was specified as IXPathNavigable
, XslCompiledTransform
doesn't reload the cache. It calls IXPathNavigable.CreateNavigator()
and uses this navigator as its cache. In this case, if the stylesheet contains xsl:strip-space
or xsl:preserve-space
instructions, XslCompiledTransform
raises an error because it can't properly apply whitespace stripping rules.
Transformation is started by applying all template rules to the current node in the XML tree. In most cases the current node will be the root node (one that matches pattern "/"). XslCompiledTransform
allows a client application to choose what node should be current at transformation start by providing input document as XPathNavigator
positioned to this node. Global variables are calculated "lazily" (on first use) and the context node for them is always the root node of the input document even when the transformation has been started from a different node.
This behavior is key to allowing to rerun parts of the transformation. XslTransform
, by contrast, did not support this feature. It always starts transformation from the root node.
Depending on the Transform
overload called, a client application may receive transformation results in one of these forms: Stream
, TextWriter
, XmlWriter
, or XmlReader
. Internally, Transform
always generates output as a set of XmlWriter
events and then serializes these events to the requested form.
The stylesheet may contain one or more xsl:output
instructions that specify how the transformation output should be serialized. These instructions are compiled into an instance of XmlWriterSettings
class, which can be accessed via the OutputSettings
property of XslCompiledTransform
. A client application may receive the output tree directly by providing an instance of the XmlWriter
class to the Transform
method as the 'results' argument. In this case the client is responsible for output serialization. When Transform
is called with Stream
or TextWriter
as the 'result' argument, XslCompiledTransform
internally creates XmlWriter
by calling XmlWriter.Create(result, outputSettings)
and then uses this writer to serialize transformation output.
Here is a WinDiff style comparison of XslTransform
and XslCompiledTransform
APIs:
public sealed class XslTransform {
public sealed class XslCompiledTransform {
// Constructors
public XslTransform();
public XslCompiledTransform() { }
// New constructor allows you to debug stylesheets
public XslCompiledTransform(bool enableDebug);
// Properties
public XmlResolver XmlResolver { set ; }
// This property was not thread-safe, and thus removed from XslCompiledTransform
public XmlWriterSettings OutputSettings { get; }
public TempFileCollection TemporaryFiles { get; }
// Load stylesheet from XmlReader
public void Load(XmlReader stylesheet);
public void Load(XmlReader stylesheet, XmlResolver resolver);
public void Load(XmlReader stylesheet, XmlResolver resolver, Evidence evidence);
public void Load(XmlReader stylesheet, XsltSettings settings, XmlResolver stylesheetResolver);
// Load stylesheet from IXPathNavigable
public void Load(IXPathNavigable stylesheet);
public void Load(IXPathNavigable stylesheet, XmlResolver resolver);
public void Load(IXPathNavigable stylesheet, XmlResolver resolver, Evidence evidence);
public void Load(IXPathNavigable stylesheet, XsltSettings settings, XmlResolver stylesheetResolver);
// Load stylesheet from XPathNavigator
public void Load(XPathNavigator stylesheet);
public void Load(XPathNavigator stylesheet, XmlResolver resolver);
public void Load(XPathNavigator stylesheet, XmlResolver resolver, Evidence evidence);
// In .NET Framework 2.0 XPathNavigator implements IXPathNavigable, so these overloads are not needed
// Load stylesheet from URI
public void Load(string url);
public void Load(string url, XmlResolver resolver);
public void Load(string stylesheetUri);
public void Load(string stylesheetUri, XsltSettings settings, XmlResolver stylesheetResolver);
// Transform document read from XmlReader
public void Transform(XmlReader input, XmlWriter results);
public void Transform(XmlReader input, XsltArgumentList arguments, XmlWriter results);
public void Transform(XmlReader input, XsltArgumentList arguments, TextWriter results);
public void Transform(XmlReader input, XsltArgumentList arguments, Stream results);
public void Transform(XmlReader input, XsltArgumentList arguments, XmlWriter results, XmlResolver documentResolver);
// Transform IXPathNavigable to XmlReader
public XmlReader Transform(IXPathNavigable input, XsltArgumentList args);
public XmlReader Transform(IXPathNavigable input, XsltArgumentList args, XmlResolver resolver);
// Not implemented in XslCompiledTransform
// Transform IXPathNavigable to XmlWriter
public void Transform(IXPathNavigable input, XsltArgumentList args, XmlWriter output);
public void Transform(IXPathNavigable input, XsltArgumentList args, XmlWriter output, XmlResolver resolver);
public void Transform(IXPathNavigable input, XmlWriter results);
public void Transform(IXPathNavigable input, XsltArgumentList arguments, XmlWriter results);
// Transform IXPathNavigable to TextWriter
public void Transform(IXPathNavigable input, XsltArgumentList args, TextWriter output);
public void Transform(IXPathNavigable input, XsltArgumentList args, TextWriter output, XmlResolver resolver);
public void Transform(IXPathNavigable input, XsltArgumentList arguments, TextWriter results);
// Transform IXPathNavigable to Stream
public void Transform(IXPathNavigable input, XsltArgumentList args, Stream output);
public void Transform(IXPathNavigable input, XsltArgumentList args, Stream output, XmlResolver resolver);
public void Transform(IXPathNavigable input, XsltArgumentList arguments, Stream results);
// Transform XPathNavigator
public XmlReader Transform(XPathNavigator input, XsltArgumentList args, XmlResolver resolver);
public XmlReader Transform(XPathNavigator input, XsltArgumentList args);
public void Transform(XPathNavigator input, XsltArgumentList args, XmlWriter output, XmlResolver resolver);
public void Transform(XPathNavigator input, XsltArgumentList args, XmlWriter output);
public void Transform(XPathNavigator input, XsltArgumentList args, Stream output, XmlResolver resolver);
public void Transform(XPathNavigator input, XsltArgumentList args, Stream output);
public void Transform(XPathNavigator input, XsltArgumentList args, TextWriter output, XmlResolver resolver);
public void Transform(XPathNavigator input, XsltArgumentList args, TextWriter output);
// In .NET Framework 2.0 XPathNavigator implements IXPathNavigable, so these overloads are not needed
// Transform document read from URI
public void Transform(String inputfile, String outputfile);
public void Transform(String inputfile, String outputfile, XmlResolver resolver);
public void Transform(string inputUri, string resultsFile);
public void Transform(string inputUri, XmlWriter results);
public void Transform(string inputUri, XsltArgumentList arguments, XmlWriter results);
public void Transform(string inputUri, XsltArgumentList arguments, TextWriter results);
public void Transform(string inputUri, XsltArgumentList arguments, Stream results);
}
As you can see, the APIs of the classes are very similar. The major differences are:
XslCompiledTransform
omitsTransform
overloads that return anXmlReader
object.Load
overloads that takeEvidence
have been replaced by ones takingXsltSettings
.XslCompiledTransform
introduces two new properties,OutputSettings
andTemporaryFiles
, and one additional constructor taking theenableDebug
flag.
Let's discuss each of these in turn.
The XslTransform
class had several Transform
overloads that return transformation results in form of an XmlReader
object. These overloads were mostly used to load the transformation results into an in-memory representation (such as XmlDocument
or XPathDocument
) without incurring the overhead of serialization and deserialization of the resulting XML tree:
// Load the stylesheet
XslTransform xslt = new XslTransform();
xslt.Load("MyStylesheet.xsl");
// Transform input document to XmlDocument for further processing
XmlDocument doc = new XmlDocument();
doc.Load(xslt.Transform(input, (XsltArgumentList)null));
Due to architectural and performance reasons, XslCompiledTransform
does not support transforming to XmlReader
. However, in .NET Framework 2.0 the XPathNavigator
class introduces new methods, which allow loading an XML tree directly from XmlWriter
. The same task may be accomplished now this way:
XmlDocument doc = new XmlDocument();
using (XmlWriter writer = doc.CreateNavigator().AppendChild()) {
xslt.Transform(input, (XsltArgumentList)null, writer);
}
Another way to obtain the transformation results in form of an XmlReader
object in an efficient way is using XslReader
class, which implements XmlReader
by running XslCompiledTransform
on a separate thread and resuming that thread each time XmlReader.Read
needs a next node. XslReader
code is available as a part of Mvp.Xml project.
Instead of Evidence
, XslCompiledTransform
's API uses a new XsltSettings
class to control stylesheet rights. This class exposes two properties, EnableScript
and EnableDocumentFunction
:
public sealed class XsltSettings {
public XsltSettings();
public XsltSettings(bool enableDocumentFunction, bool enableScript);
public bool EnableDocumentFunction { get; set; }
public bool EnableScript { get; set; }
public static XsltSettings Default {
get { return new XsltSettings(false, false); }
}
public static XsltSettings TrustedXslt {
get { return new XsltSettings(true, true); }
}
}
Script blocks and the document
function may introduce security risks and are thus disabled by default. If you trust the stylesheet and want to use those features, you need to explicitly enable them by passing an appropriately set XsltSettings
object, as shown below:
XslCompiledTransform xslt = new XslCompiledTransform();
// Disable script blocks and the document() function
// if a stylesheet came from an untrusted source
string untrustedUri = @"https://www.untrusted-site.com/meow.xsl";
XmlResolver secureResolver = new XmlSecureResolver(new XmlUrlResolver(), untrustedUri);
xslt.Load(untrustedUri, XsltSettings.Default, secureResolver);
// Enable script blocks and the document() function
// if a trusted stylesheet needs them
xslt.Load(@"C:\MyProject\purr.xsl", XsltSettings.TrustedXslt, new XmlUrlResolver());
Overloads of the Load
method that do not take an XsltSettings
argument, use XsltSettings.Default
.
If a stylesheet contains script blocks, or it is compiled with the enableDebug
flag set to true
, XslCompiledTransform
may create some temporary files in the %TEMP% folder. When the finalizer of a TempFileCollection
object (which keeps track of created temporary files), tries to remove all of them, some files may be in use by the current AppDomain
(*.DLL files) or by the debugger (*.PDB files). Those files cannot be deleted until unloading the AppDomain
or detaching the debugger. If you frequently compile XSLT stylesheets with script blocks, the %TEMP% folder may become overcrowded with temporary files left undeleted. To ensure that all temporary files will be removed, an advanced client may use the TemporaryFiles
property to save paths of temporary files for a further cleanup.
If a client application uses a Transform
overload that takes an XmlWriter
as the output object, XslCompiledTransform
ignores all xsl:output
settings specified in the stylesheet. In this case the client is responsible for output serialization. It may control serialization process by either passing a custom implementation of XmlWriter
or adjusting the properties of the standard XmlTextWriter
. If the client needs to know serialization settings specified in the stylesheet, it may obtain them through the XslCompiledTransform.OutputSettings
property. Suppose, for example, that the client needs to turn character checking off, but respect other xsl:output
settings. It may use the following code to achieve that:
// Load the stylesheet
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("MyStylesheet.xsl");
// Clone its output settings and turn character checking off
XmlWriterSettings ws = xslt.OutputSettings.Clone();
ws.CheckCharacters = false;
// Run the transformation with changed output settings
xslt.Transform("MyDocument.xml", XmlWriter.Create(Console.Out, ws));
For a number of error cases, the XSLT specification leaves XSLT processors flexibility to either signal an error, or recover by taking certain recovery action. The table below summarizes behaviors of XslTransform
and XslCompiledTransform
in such cases.
Error description | Section | XslTransform | XslCompiledTransform |
---|---|---|---|
A source node matches to both xsl:strip-space and xsl:preserve-space elements, and the conflict cannot be resolved |
3.4 | Recover | Recover |
A source node matches more than one template rule, and the conflict cannot be resolved | 5.5 | Recover | Recover |
A namespace URI is declared to be an alias for multiple different namespace URIs with the same highest import precedence | 7.1.1 | Recover | Recover |
The effective value of the name attribute of xsl:element is not a valid QName |
7.1.2 | Error | Error |
The effective value of the name attribute of xsl:attribute is not a valid QName |
7.1.3 | Error | Error |
Adding an attribute to an element after children have been added to it | 7.1.3 | Recover | Error |
Creating an attribute with the name xmlns |
7.1.3 | Recover | Error |
Adding an attribute to a node that is not an element | 7.1.3 | Recover | Error |
Creating nodes other than text nodes during the instantiation of the content of the xsl:attribute element. |
7.1.3 | Recover | Error |
Two attribute set definitions with the same expanded-name and the same highest import precedence contain an attribute in common | 7.1.4 | Recover | Recover |
The effective value of the name attribute of the xsl:processing-instruction element is not both a NCName and a PITarget |
7.3 | Recover | Error |
Instantating the content of xsl:processing-instruction creates nodes other than text nodes |
7.3 | Recover | Error |
The result of instantiating the content of the xsl:processing-instruction contains the string "?>" |
7.3 | Recover | Recover |
The result of instantiating the content of the xsl:comment contains the string "--" or ends with "-" |
7.4 | Recover | Recover |
The result of instantiating the content of the xsl:comment creates nodes other than text nodes |
7.4 | Recover | Error |
The sequence of nodes created by instantiating the template within a variable-binding element contains an attribute node or a namespace node | 11.2 | Recover | Error |
There is an error retrieving the resource from the URI passed into the document function | 12.1 | Recover | Recover/Error1 |
The URI reference in the document function contains a fragment identifier and there is an error processing the fragment identifier2 | 12.1 | Recover | Recover/Error1 |
There are multiple attributes with the same name (except for cdata-section-elements ) in xsl:output with the same import precedence |
16 | Recover | Recover |
The encoding specified in the encoding attribute of the xsl:output element is not supported |
16.1 | Recover | Recover |
Disabling output escaping for a text node that is used for something other than a text node in the result tree | 16.4 | Recover | Recover |
Converting a result tree fragment to a number or string if the result tree fragment contains a text node with output escaping enabled. | 16.4 | Recover | Recover |
Output escaping is disabled for a character that is not representable in the encoding that the XSLT processor is using for output | 16.4 | Recover | Recover |
The second argument node-set to the document function is empty and the URI reference is relative3 |
E14 | Recover | Recover/Error1 |
The effective value of the value attribute of the xsl:number element is NaN, infinite, or less than 0.5 |
E24 | Recover | Recover |
Adding a namespace node to an element after children have been added to it or after attributes have been added to it | E25 | Recover | Error |
1 Behavior depends on the document resolver passed to the Transform
method. See the section devoted to the document
function.
2 The default resolver, XmlUrlResolver
, always ignores fragment identifiers. However, custom resolvers may regard them.
3 XmlUrlResolver
will pass the relative URI reference to Path.GetFullPath
and resolve it relative to the current directory. Custom resolvers may behave differently.
In XSLT both stylesheet modules and source documents are XML files. There is a lot of similarity in loading them. Here we summarize how XslCompiledTransform
loads stylesheet modules and source documents and then we will see where its behavior is different from XslTransform
.
XslCompiledTransform
uses XmlReader
to read both stylesheets and source documents. In both cases more than one XML file can be used. A stylesheet module may import or include other stylesheet modules; to load additional source documents, the document
function can be used.
XslCompiledTransform
delegates all work related to external URIs access to XmlResolver
. To load the principal stylesheet and all includes/imports, XslCompiledTransform
uses instance of XmlResolver
which was passed to the Load
method. To load the source document and all subsequent documents, XslCompiledTransform
uses XmlResolver
passed to the Transform
method.
When the overload of the Load
/Transform
method that doesn't have XmlResolver
argument is called, XmlUrlResolver
is used to load subsequent stylesheets and documents. When null
is passed as an XmlResolver
argument to the Load
/Transform
method, loading of subsequent stylesheets/documents is disabled.
A client application may pass XmlReader
, URI string
or IXPathNavigable
to Load
/Transform
methods. System.Uri
will be passed to XmlResolver
and resolved to XmlReader
, Stream
or IXPathNavigable
.
For subsequent stylesheets/documents XmlResolver
returns to Proccessor XmlReader
, Stream
or IXPathNavigable
.
In case when input is Stream
to load XML Processor creates XmlTextReader
. XmlTextReader
has set of properties which control reader's behavior. (Most important properties are Normalization
, ProhibitDtd
, WhitespaceHandling
, XmlResolver
; see documentation for XmlTextReader
on meaning of this properies.)
When XslCompiledTransform
creates the first reader, one that is used for reading data passed directly to Load
/Transform
methods, it sets the reader setting the following way:
XmlReaderSettings rs = new XmlReaderSettings();
rs.ConformanceLevel = ConformanceLevel.Document;
rs.XmlResolver = null;
rs.ProhibitDtd = true;
rs.CloseInput = true;
For each subsequent stylesheet/document XslCompiledTransform
creates XmlTextReader
with the same reader settings that the first XmlReader
has. This guarantees consistency in loading stylesheets and source documents.
If you need to use specific reader settings in stylesheet/document load process, you have to pass XmlReader
created with these settings to Load
/Transform
methods. If you want XmlReader
for subsequent stylesheet/document document to have different reader settings, you should implement a custom XmlResolver
, which returns an XmlReader
with required reader settings, and pass it to a Load
/Transform
method.
In contrast, XslTransform
always created helper XmlTextReader
objects with default settings. If a client application provided the Load
/Transform
method with an XmlReader
that has non-default reader settings, those reader settings were not regarded on subsequent document loads.
XslTransform
swallowed any exceptions thrown during execution of the document
function, returning an empty node-set. All possible run-time errors (e.g., network share cannot be accessed) were masked, and clients had no means to control that.
In contrast, XslCompiledTransform
class does not swallow exceptions, but rethrows them wrapped in an XslTransformException
. However, you can still implement XslTransform
's behavior—if the GetEntity
method of your custom XmlResolver
returns null
, it is treated as an empty node-set, and no errors will be reported.
When you used XslTransform
, the GetEntity
method of your XmlResolver
had to return either Stream
or XPathNavigator
. With XslCompiledTransform
, a resolver can return either Stream
, XmlReader
, or IXPathNavigable
(and, therefore, XPathNavigator
). The option of returning XmlReader
is useful if you want to have precise control of loading documents, for example, to control whitespace handling, DTD handling (prohibit or allow processing a DTD), compatibility issues (use an old XmlTextReader
or a new reader created by XmlReader.Create
), etc.
It is common to use document('')
to refer to the document node of the containing stylesheet module. Please note that the base URI of the stylesheet module must be known in order to make it work. For example, if you create an XmlReader
over a stream without specifying its base URI, XSLT engine will not resolve the empty string reference correctly unless you have provided a custom XmlResolver
that handles such a reference in a special way.
Both XslTransform
and XslCompiledTransform
allow extending XSLT language through script blocks (ms:script
elements) included in the stylesheet and extension objects passed added to XsltArgumentList
. Here we outline differences between XslTransform
and XslCompiledTransform
in implementing these features.
Both XSLT engines use CodeDom to compile script blocks. All script blocks implementing the same namespace are concatenated and compiled into a single class. Methods of that class may be called from within XPath expressions contained in the stylesheet.
XslCompiledTransform
introduces two new restrictions on use of scripts:
- Only public methods may be called from XPath expressions.
- Overloads are distinct only base on number of arguments. If more then one overload has the same number of arguments, an exception will be raised.
In XslCompiledTransform
a binding (method name lookup) to script functions happens at compile time, and stylesheets that worked with XslTranform
may cause an exception when loaded with XslCompiledTransform
.
XslCompiledTransform
allows the ms:script
element to start with ms:using
and ms:assembly
child elements. The former declares an additional namespace, the latter refers an additional assembly for use in a script block.
The only difference in implementation of extension objects is that multiple overloads with the same number of arguments are prohibited now.
XslTransform
allowed returning a node-set from an extension function as an object of the XPathNodeIterator
class. With XslCompiledTransform
you have more alternatives: a node-set may be returned as XPathNodeIterator
, XPathNavigator[]
, or XPathNavigator
(if the node-set consists of a single node).
XslCompiledTransform
makes it easier to migrate from MSXML to managed XSLT implementation by supporting some MSXML extensions. Everywhere in this section the ms
prefix denotes the urn:schemas-microsoft-com:xslt
namespace URI. Another frequently used prefix for this namespace URI is msxsl
. Of course, you may use any other prefix in your stylesheet provided it is bound to the same URI.
XslTransform
required the argument of the ms:node-set
function to be an RTF (result tree fragment), throwing an exception for an argument of any other type. Behavior of this function in XslCompiledTransform
is aligned with the behavior of the same function in MSXML and exsl:node-set
, which allow converting a value of an arbitrary type into a text node containing a string representation of that value. For example, ms:node-set(1 div 0)
creates a text node with the value 'Infinity'
.
XslTransform
did not recognize the ms:version
property, returning an empty string. XslCompiledTransform
supports the ms:version
system property. For example, system-property('ms:version')
returns a string representing the version of the assembly implementing XslCompiledTransform
in the same format as returned by Assembly.ImageRuntimeVersion
property ('v2.0.50727'
for .NET Framework 2.0).
MSXML provides a number of XPath extension functions to facilitate developing XSLT stylesheets. XslTransform
did not support them. XslCompiledTransform
supports all those functions except schema-related ones:
Function | Signature and description |
---|---|
ms:string-compare | number ms:string-compare(string x, string y[, string language[, string options]])Performs lexicographical string comparison. |
ms:utc | string ms:utc(string time)Converts the prefixed date/time related values into Coordinated Universal Time and into a fixed (normalized) representation that can be sorted and compared lexicographically. |
ms:namespace-uri | string ms:namespace-uri(string name)Resolves the prefix part of a qualified name into a namespace URI. |
ms:local-name | string ms:local-name(string name)Returns the local name part of a qualified name by stripping out the namespace prefix. |
ms:number | number ms:number(string value)Takes a string argument in XSD format and converts it into an XPath number. |
ms:format-date | string ms:format-date(string datetime[, string format[, string locale]])Converts standard XSD date formats to characters suitable for output. |
ms:format-time | string ms:format-time(string datetime[, string format[, string locale]])Converts standard XSD time formats to characters suitable for output. |
The following schema-related XPath extension functions are not supported natively by XslCompiledTransform
, but may be implemented as extension functions:
Function | Signature and description |
---|---|
ms:type-is | boolean ms:type-is(string URI, string local-name)Compares the current node's data type against the specified node type. |
ms:type-local-name | string ms:type-local-name([node-set nodes])Returns the nonqualified name of the XSD type of the current node or the first node (in document order) in the provided node-set. |
ms:type-namespace-uri | string ms:type-namespace-uri([node-set nodes])Returns the namespace URI associated with the XSD type of the current node or the first node (in document order) in the provided node-set. |
ms:schema-info-available | boolean ms:schema-info-available()Returns true if XSD information is available for the current node. |
If you migrate from MSXML, and your stylesheets contain script blocks, you will likely have to rework them, because the System.Xml assembly uses a different object model to represent nodes and node-sets than MSXML does. Moreover, managed JScript .NET and Visual Basic .NET, supported by XslCompiledTransform
, differ to some extent from their native counterparts, JScript and VBScript.
In the .NET Framework 2.0, this gap is narrowed a bit. XPathNodeIterator
implements the IEnumerable
interface. This allows iterating node-set objects with JScript's foreach
instruction.
With MSXML you can specify an initial mode, which the transformation would start in, using the setStartMode
method of the IXSLProcessor
interface. Both XslTransform
and XslCompiledTransform
do not provide means to specify a start mode, however you may usually simulate that by passing the name of the start mode as an additional parameter to your stylesheet and adding a new 'start template' containing a switch table:
<xsl:stylesheet version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform">
<!-- Import your main stylesheet here -->
<xsl:import href="main.xsl"/>
<!-- Set this parameter to simulate setting a start mode -->
<xsl:param name="start-mode" select="''"/>
<xsl:template match="/">
<!-- Switch mode according to the value of $start-mode -->
<xsl:choose>
<xsl:when test="$start-mode=''">
<!-- Continue processing in the default mode -->
<xsl:apply-imports/>
</xsl:when>
<xsl:when test="$start-mode='foo'">
<!-- Switch to mode foo -->
<xsl:apply-templates select="/" mode="foo"/>
</xsl:when>
<xsl:when test="$start-mode='bar'">
<!-- Switch to mode bar -->
<xsl:apply-templates select="/" mode="bar"/>
</xsl:when>
...
<xsl:otherwise>
<xsl:message terminate="yes">Invalid start-mode</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
You may be surprised at seeing System.Data.SqlXml assembly on a call stack. System.Data.SqlXml is a helper assembly containing a part of XslCompiledTransform
implementation. It is not supposed to be used directly, and there is no guarantee that its API will not be changed in future .NET Framework releases.
Authors: Sergey Dubinets, Anton Lapounov
- Anonymous
May 08, 2006
XslCompiledTransform in .NET Framework version 2.0, Differences in Behavior