<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Anton Lapounov: XML XSLT and Beyond</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/antosha/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/antosha/feed.xml</link>
    <description>Secrets of using XML and XSLT in the .NET world</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:45:52 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>XSLTC — Compile XSLT to .NET Assembly</title>
      <link>https://docs.microsoft.com/archive/blogs/antosha/xsltc-compile-xslt-to-net-assembly</link>
      <pubDate>Mon, 28 May 2007 20:13:00 GMT</pubDate>
      <dc:creator><![CDATA[antosha]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/antosha/2007/05/28/xsltc-compile-xslt-to-net-assembly/</guid>
      <description><![CDATA[In my two previous posts I described a potential performance hit caused by XSLT-to-MSIL compilation...]]></description>
      <content:encoded><![CDATA[<P>In my two <A href="https://blogs.msdn.com/antosha/archive/2006/07/16/667221.aspx" mce_href="https://blogs.msdn.com/antosha/archive/2006/07/16/667221.aspx">previous</A> <A href="https://blogs.msdn.com/antosha/archive/2006/07/24/677560.aspx" mce_href="https://blogs.msdn.com/antosha/archive/2006/07/24/677560.aspx">posts</A> I described a potential performance hit caused by XSLT-to-MSIL compilation and JIT-compilation when you load and run some XSLT stylesheet with the <CODE>XslCompiledTransform</CODE> engine for the first time. Since the .NET Framework 2.0 did not allow you to save compiled stylesheets, you had to pay the compilation price on each application run.</P>
<H4>XSLT Compiler Utility</H4>
<P>The good news is we are providing the XSLT Compiler command-line utility <CODE>xsltc.exe</CODE> (announced <A href="https://blogs.msdn.com/xmlteam/archive/2007/02/02/xml-features-in-the-february-ctp-of-visual-studio-orcas.aspx" mce_href="https://blogs.msdn.com/xmlteam/archive/2007/02/02/xml-features-in-the-february-ctp-of-visual-studio-orcas.aspx">here</A>) that can be used to compile multiple stylesheets into one assembly. The changes to the System.Xml assembly required for this utility to work are shipped with .NET Framework 2.0 Service Pack 1, and the utility itself is shipped with Windows SDK 6.0, which absorbs .NET Framework SDK. Both these components will be installed by Visual Studio 2008. Below is the usage screen of <CODE>xsltc.exe</CODE>:</P><PRE class=Console>C:\&gt;<SPAN style="COLOR: yellow">xsltc.exe /?</SPAN>
Microsoft (R) XSLT Compiler version 3.5
[Microsoft (R) .NET Framework version 2.0.50727]
Copyright (C) Microsoft Corporation. All rights reserved.

<SPAN style="COLOR: lightgreen">xsltc</SPAN> [options] [<SPAN style="COLOR: lightgreen">/class:</SPAN>&lt;name&gt;] &lt;source file&gt; [[<SPAN style="COLOR: lightgreen">/class:</SPAN>&lt;name&gt;] &lt;source file&gt;...]

                      XSLT Compiler Options

                        - OUTPUT FILES -
<SPAN style="COLOR: lightgreen">/out:</SPAN>&lt;file&gt;             Specify name of binary output file (default: name of the first file)
<SPAN style="COLOR: lightgreen">/platform:</SPAN>&lt;string&gt;      Limit which platforms this code can run on: <SPAN style="COLOR: lightgreen">x86</SPAN>, <SPAN style="COLOR: lightgreen">Itanium</SPAN>, <SPAN style="COLOR: lightgreen">x64</SPAN>, or <SPAN style="COLOR: lightgreen">anycpu</SPAN>,
                        which is the default

                        - CODE GENERATION -
<SPAN style="COLOR: lightgreen">/class:</SPAN>&lt;name&gt;           Specify name of the class for compiled stylesheet (short form: <SPAN style="COLOR: lightgreen">/c</SPAN>)
<SPAN style="COLOR: lightgreen">/debug</SPAN>[<SPAN style="COLOR: lightgreen">+</SPAN>|<SPAN style="COLOR: lightgreen">-</SPAN>]             Emit debugging information
<SPAN style="COLOR: lightgreen">/settings:</SPAN>&lt;list&gt;        Specify security settings in the format (<SPAN style="COLOR: lightgreen">dtd</SPAN>|<SPAN style="COLOR: lightgreen">document</SPAN>|<SPAN style="COLOR: lightgreen">script</SPAN>)[<SPAN style="COLOR: lightgreen">+</SPAN>|<SPAN style="COLOR: lightgreen">-</SPAN>]<SPAN style="COLOR: lightgreen">,</SPAN>...
                        <SPAN style="COLOR: lightgreen">Dtd</SPAN> enables DTDs in stylesheets, <SPAN style="COLOR: lightgreen">document</SPAN> enables document() function,
                        <SPAN style="COLOR: lightgreen">script</SPAN> enables &lt;msxsl:script&gt; element

                        - MISCELLANEOUS -
<SPAN style="COLOR: lightgreen">@</SPAN>&lt;file&gt;                 Insert command-line settings from a text file
<SPAN style="COLOR: lightgreen">/help</SPAN>                   Display this usage message (short form: <SPAN style="COLOR: lightgreen">/?</SPAN>)
<SPAN style="COLOR: lightgreen">/nologo</SPAN>                 Suppress compiler copyright message
</PRE>
<P>The most useful options are <CODE>/class</CODE> and <CODE>/out</CODE>. If you have not specified the class name for some stylesheeet, it is defaulted to the name of the file containing that stylesheet, omitting the extension. The <CODE>/debug</CODE> option disables practically all optimizations (beware of performance degradation!) and creates a PDB file for the output assembly, which allow debugging stylesheets with a debugger. For security reasons, DTDs in stylesheets, the <CODE>document</CODE> XSLT function, and <CODE><A href="https://msdn2.microsoft.com/en-us/library/ms256042.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/ms256042.aspx">msxsl:script</A></CODE> elements are disabled by default; you have to explicitly enable them using the <CODE>/settings</CODE> option if required. Each stylesheet is compiled into an abstract class, which can be loaded later by a new <CODE>XslCompiledTransform.Load</CODE> overload:</P><PRE class=Code><SPAN style="COLOR: blue">public</SPAN> <SPAN style="COLOR: blue">void</SPAN> Load(<SPAN style="COLOR: teal">Type</SPAN> compiledStylesheet);
</PRE>
<P>Compiling stylesheets into an assembly both simplifies the deployment (you don't have to deploy multiple stylesheet files) and eliminates XSLT-to-MSIL compilation time. Moreover, you may also eliminate JIT-compilation time by installing the resulting assembly in the <A href="https://msdn2.microsoft.com/en-us/library/6t9t5wcf.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/6t9t5wcf.aspx">native image cache</A>.</P>
<H4>How to Use It</H4>
<P>Let us take, for example, a couple of the <A href="https://en.wikipedia.org/wiki/Docbook" mce_href="https://en.wikipedia.org/wiki/Docbook">DocBook</A> stylesheets, which had the <A href="https://blogs.msdn.com/antosha/archive/2006/07/24/677560.aspx#DocBookJitTime" mce_href="https://blogs.msdn.com/antosha/archive/2006/07/24/677560.aspx#DocBookJitTime">worst</A> JIT-compilation time in my previous experiment, and compile them:</P><PRE class=Console>C:\docbook-xsl-1.72.0&gt;<SPAN style="COLOR: yellow">xsltc /settings:dtd+,document+ /class:DocBookToHtml html\docbook.xsl /class:DocBookToFO fo\docbook.xsl</SPAN>
</PRE>
<P>If you run the ILDASM tool on the resulting <CODE>docbook.dll</CODE> assembly, you will see two classes, <CODE>DocBookToFO</CODE> and <CODE>DocBookToHtml</CODE> generated for the stylesheets specified on the command line along with two helper <CODE>$ArrayType$</CODE>... classes used internally to initialize XSLT engine runtime tables:</P>
<P style="TEXT-ALIGN: center"><IMG src="https://antosha.com/images/DocBook.dll.gif" mce_src="https://antosha.com/images/DocBook.dll.gif"></P>
<P style="FONT-WEIGHT: bold; TEXT-ALIGN: center">Assembly with compiled DocBook stylesheets</P>
<P>To use compiled stylesheets from your favorite .NET language, you need to add a reference to <CODE>docbook.dll</CODE> to your project, and pass the desired class to the <CODE>XslCompiledTransform.Load</CODE> method. After that you may call <CODE>Transform</CODE> methods on the loaded <CODE>XslCompiledTransform</CODE> object the usual way:</P><PRE class=Code><SPAN style="COLOR: teal">XslCompiledTransform</SPAN> stylesheet = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: teal">XslCompiledTransform</SPAN>();
stylesheet.Load(<SPAN style="COLOR: blue">typeof</SPAN>(<SPAN style="COLOR: teal">DocBookToHtml</SPAN>));
stylesheet.Transform(<SPAN style="COLOR: brown">"input.xml"</SPAN>, <SPAN style="COLOR: brown">"output.html"</SPAN>);
</PRE>
<P>To improve startup time you may choose to "pre-JIT" the assembly, installing a native image for it in the native image cache. However, before that you probably want to change the preferred base address of the assembly to avoid rebasing (I recommend reading <A href="https://msdn.microsoft.com/msdnmag/issues/06/02/CLRInsideOut/" mce_href="https://msdn.microsoft.com/msdnmag/issues/06/02/CLRInsideOut/">Improving Application Startup Time</A> and <A href="https://msdn.microsoft.com/msdnmag/issues/05/04/NGen/" mce_href="https://msdn.microsoft.com/msdnmag/issues/05/04/NGen/">NGen Revs Up Your Performance with Powerful New Features</A> articles). The <CODE>xsltc.exe</CODE> utility does not support the <CODE><A href="https://msdn2.microsoft.com/en-us/library/b1awdekb.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/b1awdekb.aspx">/baseaddress</A></CODE> option, but you may use either <CODE>rebase.exe</CODE> or <CODE><A href="https://msdn2.microsoft.com/en-us/library/hh7adf4f.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hh7adf4f.aspx">editbin.exe</A></CODE> tool, both of which come with Visual Studio<SUP>®</SUP>:</P><PRE class=Console>C:\docbook-xsl-1.72.0&gt;<SPAN style="COLOR: yellow">editbin.exe /rebase:base=0x60000000 docbook.dll /nologo</SPAN>

C:\docbook-xsl-1.72.0&gt;<SPAN style="COLOR: yellow">ngen install docbook.dll /nologo</SPAN>
Installing assembly C:\docbook-xsl-1.72.0\docbook.dll
Compiling 1 assembly:
    Compiling assembly C:\docbook-xsl-1.72.0\docbook.dll ...
docbook, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
</PRE>
<P>You may ask why we decided to compile stylesheets to abstract classes instead of implementing some common interface similar to <CODE><A href="https://mvp-xml.sourceforge.net/api/2.0/T_Mvp_Xml_Common_Xsl_IXmlTransform_Members.html" mce_href="https://mvp-xml.sourceforge.net/api/2.0/T_Mvp_Xml_Common_Xsl_IXmlTransform_Members.html">IXmlTransform</A></CODE> from Mvp.Xml project. There were two main reasons. First, <CODE>System.Xml</CODE> is a <A href="https://blogs.msdn.com/somasegar/archive/2006/05/18/601354.aspx" mce_href="https://blogs.msdn.com/somasegar/archive/2006/05/18/601354.aspx">"red" assembly</A>, and changes in the red bits have been greatly limited in Orcas. We tried to make public API changes as minimal as possible. Second, implementing XSLT 2.0 in the next release of the .NET Framework will probably require us to change the interface anyway.</P>
<H4>Script Assemblies</H4>
<P>If the stylesheet contains <CODE>msxsl:script</CODE> elements, their content is compiled to one or more separate assemblies using the <A href="https://msdn2.microsoft.com/en-us/library/650ax5cx.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/650ax5cx.aspx">CodeDOM</A> technology. Since the CodeDOM does not allow having code snippets in different languages in a single assembly, one script assembly per script language is created. Suppose, for example, that the stylesheet <CODE>MyTransform.xsl</CODE> contains C# and Visual Basic .NET script blocks. When you compile it, three assemblies will be created: <CODE>MyTransform.dll</CODE>, containing compiled XSLT code, <CODE>MyTransform.Script.cs.dll</CODE>, containing compiled C# script blocks, and <CODE>MyTransform.Script.vb.dll</CODE>, containing compiled Visual Basic .NET script blocks. You may merge script assemblies with the XSLT assembly using the <A href="https://research.microsoft.com/~mbarnett/ILMerge.aspx" mce_href="https://research.microsoft.com/~mbarnett/ILMerge.aspx">ILMerge</A> utility:</P><PRE class=Console>C:\MyTransform&gt;<SPAN style="COLOR: yellow">ILMerge /out:MyTransform.dll MyTransform.dll MyTransform.Script.cs.dll MyTransform.Script.vb.dll</SPAN>
</PRE>
<H4>Limitations</H4>
<P>Currently <CODE>xsltc.exe</CODE> does not allow to embed XML files as resources. Why might you need that? Suppose that the stylesheet <CODE>C:\MyTransform\MyTransform.xsl</CODE> contains relative document references <CODE>document('')</CODE> and <CODE>document('config.xml')</CODE>. If you compile it and deploy to another machine, it will try to read <CODE>C:\MyTransform\MyTransform.xsl</CODE> and <CODE>C:\MyTransform\config.xml</CODE> file respectively, which will result in an error unless you deploy <CODE>MyTransform.xsl</CODE> and <CODE>config.xml</CODE> in the same folder as on the build machine. You may think that relative document references should be resolved relative to the location of the compiled XSLT assembly, or that all documents referenced with relative URIs should be embedded in the assembly, but there are always cases when you need a different behavior. Fortunately, this problem may be resolved by modifying <CODE>xsltc.exe</CODE> to use a custom <CODE>XmlResolver</CODE>; I may write on this later.</P>
<P>Another limitation is that while <CODE>XslCompiledTransform</CODE> compiles a stylesheet to a set of unloadable <CODE><A href="https://msdn2.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx">DynamicMethod</A></CODE>s, an assembly generated by <CODE>xsltc.exe</CODE> cannot be unloaded until you shut down all <CODE>AppDomain</CODE>s that used it (an <A href="https://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx" mce_href="https://blogs.msdn.com/jasonz/archive/2004/05/31/145105.aspx">infamous</A> CLR limitation). This should not be a problem if you have a small set of fixed stylesheets, but becomes a real issue in server scenarios when thousand of stylesheets are generated dynamically based on user settings and customizations. We are actively investigating possible solutions for server scenarios, which do not require complicated <A href="https://blogs.msdn.com/suzcook/archive/2003/07/08/57211.aspx" mce_href="https://blogs.msdn.com/suzcook/archive/2003/07/08/57211.aspx"><CODE>AppDomain</CODE> manipulations</A>.</P>
<H4>Under the Hood</H4>
<P>Under the hood, <CODE>xsltc.exe</CODE> is a wrapper around the new <CODE>XslCompiledTransform.CompileToType</CODE> static method. You don't need to know about it unless you are developing your <A href="https://www.tkachenko.com/blog/archives/000688.html" mce_href="https://www.tkachenko.com/blog/archives/000688.html">own version</A> of the XSLT compiler. We expect that very few people will ever need to call this low-level method directly, as most will use <CODE>xsltc.exe</CODE> and optionally do some post-processing with other command-line utilities. However, for the sake of completeness, here is its brief description. (<SPAN style="COLOR: red">WARNING:</SPAN> The signature of the <CODE>CompileToType</CODE> method in beta releases of .NET Framework 2.0 SP1 may differ from the one given below.)</P><PRE class=Code><SPAN style="COLOR: green">// Compiles an XSLT stylesheet to a System.Type</SPAN>
<SPAN style="COLOR: blue">public static</SPAN> <SPAN style="COLOR: teal">CompilerErrorCollection</SPAN> CompileToType(
    <SPAN style="COLOR: teal">XmlReader</SPAN> stylesheet,
    <SPAN style="COLOR: teal">XsltSettings</SPAN> settings,
    <SPAN style="COLOR: teal">XmlResolver</SPAN> stylesheetResolver,
    <SPAN style="COLOR: blue">bool</SPAN> debug,
    <SPAN style="COLOR: teal">TypeBuilder</SPAN> typeBuilder,
    <SPAN style="COLOR: blue">string</SPAN> scriptAssemblyPath);
</PRE>
<P><A onclick="CompileToTypeParameters.style.display = (CompileToTypeParameters.style.display != 'none') ? 'none' : 'block'; return false;" href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=5780&amp;postid=2955402#" mce_href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=5780&amp;postid=2955402#"><STRONG>Parameters...</STRONG></A><BR>
<DIV id=CompileToTypeParameters style="DISPLAY: none"><STRONG>stylesheet</STRONG><BR>
<DIV style="PADDING-LEFT: 3em">The <CODE>XmlReader</CODE> positioned on the beginning of the stylesheet.</DIV><BR><STRONG>settings</STRONG><BR>
<DIV style="PADDING-LEFT: 3em">The <CODE>XsltSettings</CODE> to apply to the stylesheet. If this is <CODE>null</CODE>, the <CODE>XsltSettings.Default</CODE> settings are applied.</DIV><BR><STRONG>stylesheetResolver</STRONG><BR>
<DIV style="PADDING-LEFT: 3em">The <CODE>XmlResolver</CODE> used to resolve any stylesheet modules referenced in <CODE>xsl:import</CODE> and <CODE>xsl:include</CODE> elements. If this is <CODE>null</CODE>, external resources are not resolved.</DIV><BR><STRONG>debug</STRONG><BR>
<DIV style="PADDING-LEFT: 3em"><CODE>true</CODE> to compile in debug mode; otherwise <CODE>false</CODE>. Setting this to <CODE>true</CODE> enables debugging the stylesheet with a debugger.</DIV><BR><STRONG>typeBuilder</STRONG><BR>
<DIV style="PADDING-LEFT: 3em">The <CODE>TypeBuilder</CODE> to use for the stylesheet compilation.</DIV><BR><STRONG>scriptAssemblyPath</STRONG><BR>
<DIV style="PADDING-LEFT: 3em">The base path for the assemblies generated for <CODE>msxsl:script</CODE> elements. If only one script assembly is generated, this parameter specifies the path for that assembly. In case of multiple script assemblies, a distinctive suffix will be appended to the file name to ensure uniqueness of assembly names.</DIV><BR><STRONG>Return Value</STRONG><BR>
<DIV style="PADDING-LEFT: 3em">A <CODE>CompilerErrorCollection</CODE> object containing compiler errors and warnings that indicates the results of the compilation.</DIV></DIV>
<P>Note that the first three parameters are the same as in <CODE><A href="https://msdn2.microsoft.com/en-us/library/ms163427.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/ms163427.aspx">XslCompiledTransform.Load</A></CODE> method. The <CODE>xsltc.exe</CODE> utility creates an <CODE>AssemblyBuilder</CODE> and a <CODE>MethodBuilder</CODE>, then for each stylesheet specified on the command line creates a <CODE>TypeBuilder</CODE>, and compiles the stylesheet into it using the <CODE>CompileToType</CODE> method. Compiler errors and warning returned from the <CODE>CompileToType</CODE> method are output to the console. If all stylesheets have been compiled successfully, the dynamic assembly is saved to disk. If you are new to Reflection.Emit, you may find <A href="https://blogs.msdn.com/joelpob/archive/2004/01/21/61411.aspx" mce_href="https://blogs.msdn.com/joelpob/archive/2004/01/21/61411.aspx">this</A> dynamic assembly sample code useful.</P>
<H4>Conclusion</H4>
<P>The <CODE>xsltc.exe</CODE> utility allows you to precompile XSLT stylesheets so that your application will not incur the performance penalty of XSLT-to-MSIL and JIT-compilation on the first stylesheet execution. It also makes deployment of complex XSLT solutions, consisting of dozens of files, less cumbersome and protects your source XSLT code. Multiple stylesheets may be compiled into a single assembly, and the resulting assembly may be merged with the main DLL or EXE file of your application using the ILMerge utility.</P>]]></content:encoded>
    </item>
    <item>
      <title>XslCompiledTransform Performance: Beating MSXML 4.0</title>
      <link>https://docs.microsoft.com/archive/blogs/antosha/xslcompiledtransform-performance-beating-msxml-4-0</link>
      <pubDate>Mon, 24 Jul 2006 08:29:00 GMT</pubDate>
      <dc:creator><![CDATA[antosha]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/antosha/2006/07/24/xslcompiledtransform-performance-beating-msxml-4-0/</guid>
      <description><![CDATA[Update:Transformation times for Saxon processors have been remeasured and updated based on the...]]></description>
      <content:encoded><![CDATA[<DIV style="PADDING-LEFT: 2em">
<P><STRONG>Update:</STRONG><BR>Transformation times for Saxon processors have been remeasured and updated based on the feedback received from Dimitre Novatchev and Michael Kay. I also slightly altered the text below to reflect the change in Saxon command-line arguments.</P></DIV>
<P>Interestingly enough, the first <A href="https://live.com/" mce_href="https://live.com">live.com</A> hit for the "XslCompiledTransform Performance" query at the moment is <A href="https://www.wintellect.com/cs/blogs/jprosise/archive/2005/12/13/xslcompiledtransform-performance.aspx" mce_href="https://www.wintellect.com/cs/blogs/jprosise/archive/2005/12/13/xslcompiledtransform-performance.aspx">this post</A> of Jeff Prosise, where he says he was disappointed that <CODE>XslCompiledTransform</CODE> ran just 3 times faster than <CODE>XslTransform</CODE> on a "fairly simple style sheet". He is concerned that <CODE>XslCompiledTransform</CODE> is not fast enough comparing to the good old MSXML 4.0. Well, as we will see very soon, <CODE>XslCompiledTransform</CODE> may easily outperform MSXML 4.0 by several times!</P>
<P>Here I compare transformation speed of different widely-used XSLT processors for several arbitrary chosen stylesheets. I deliberately do not consider many other important aspects, such as working set, start-up time, compilation time, scalability issues, etc., focusing on pure transformation time only. I fairly tried to make all processors compete on equal terms; however I could miss some important details, especially for Saxon, which I know very little about. So this post should in no way be considered as a thorough comparison of XSLT processors; you are encouraged to run your scenarios with different processors and pick the one that fits your needs in the best way.</P>
<P>Let's first briefly describe our today's contestants:</P>
<UL>
<LI><STRONG>MSXML 3.0</STRONG>. The native XSLT processor implemented in MSXML 3.0 is still used by default in the Internet Explorer 6.0 and 7.0. It compiled a stylesheet to a tree of "actions", each of which knew how to "execute" itself. So it worked as a pretty simple XSLT <A href="https://en.wikipedia.org/wiki/Interpreter_%28computing%29" mce_href="https://en.wikipedia.org/wiki/Interpreter_%28computing%29">interpreter</A>.</LI>
<LI><STRONG>MSXML 4.0</STRONG>. The XSLT processor in MSXML 4.0 was completely reworked. It implemented a number of optimization techniques and compiled a stylesheet to some sort of <A href="https://en.wikipedia.org/wiki/P-Code_machine" mce_href="https://en.wikipedia.org/wiki/P-Code_machine">P-code</A>, which resulted in significantly faster transformation speed. This processor is more conformant and reliable than its MSXML 3.0 predecessor. Further versions of MSXML—5.0 and 6.0—bore the same XSLT processor as MSXML 4.0, so there is no much sense to consider them separately.</LI>
<LI><STRONG>XslTransform</STRONG>. The first <A href="https://en.wikipedia.org/wiki/Managed_code" mce_href="https://en.wikipedia.org/wiki/Managed_code">managed</A> XSLT processor, <CODE>XslTransform</CODE>, was a port of MSXML 3.0 code. Unfortunately, in addition to bugs and performance issues ported from MSXML 3.0, some new ones were introduced during the porting process. <CODE>XslTransform</CODE> was good enough for many applications; however it was clear that its radical improvements were impossible without radical reworking of the code like the one happened between MSXML 3.0 and 4.0.</LI>
<LI><STRONG>XslCompiledTransform</STRONG>. The .NET Framework 2.0 presents a new managed XSLT processor, <CODE>XslCompiledTransform</CODE>, which is going to replace the obsolete <CODE>XslTransform</CODE> class. <CODE>XslCompiledTransform</CODE> operates as a true <A href="https://en.wikipedia.org/wiki/Compiler" mce_href="https://en.wikipedia.org/wiki/Compiler">compiler</A>, translating a stylesheet into a set of dynamic <A href="https://en.wikipedia.org/wiki/MSIL" mce_href="https://en.wikipedia.org/wiki/MSIL">MSIL</A> methods, which use the highly-optimized XSLT runtime library. While compiled stylesheets run amazingly fast, incurred set-up costs—XSLT-to-MSIL compilation time plus JIT-compilation time—are considerably higher than for other XSLT processors, which may hinder its adoption in some applications.</LI>
<LI><STRONG>Saxon 6.5.5</STRONG>. <A href="https://saxon.sourceforge.net/" mce_href="https://saxon.sourceforge.net/">Saxon</A> is an open-source Java implementation of XSLT 1.0, developed by Michael Kay, a great XSLT enthusiast and the editor of the XSLT 2.0 specification. Version 6.5.5 was the last XSLT 1.0 processor release. As you can conclude from Michael Kay's "<A href="https://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html" mce_href="https://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html">XSLT and XPath Optimization</A>" article, Saxon uses basically the same approach as the XSLT processor in MSXML 3.0 together with some optimization techniques.</LI>
<LI><STRONG>Saxon 8.7.3</STRONG>. The latest version of Saxon, Saxon 8.7.3, implements the recent candidate recommendations for XSLT 2.0, XQuery 1.0 and XPath 2.0, and provides better integration with the .NET platform. Though it is an XSLT <STRONG>2.0</STRONG> processor, it is interesting to know how fast it can execute XSLT 1.0 stylesheets.</LI></UL>
<P>To run tests with MSXML I used the <A href="https://www.microsoft.com/downloads/details.aspx?FamilyID=2fb55371-c94e-4373-b0e9-db4816552e41&amp;DisplayLang=en" mce_href="https://www.microsoft.com/downloads/details.aspx?FamilyID=2fb55371-c94e-4373-b0e9-db4816552e41&amp;DisplayLang=en">Msxsl.exe</A> command-line utility. I had to tweak its code a little, because the <CODE>-t</CODE> option for measuring load and transformation times failed to work on CPUs faster than 2 GHz. The utility was developed around 09/2000, and apparently some of Microsoft developers did not realize how fast processors would become in 6 years! More precisely, this part of the <CODE>Timer</CODE> class constructor <A href="https://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/windowing/timers/timerreference/timerfunctions/queryperformancefrequency.asp?frame=true" mce_href="https://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/windowing/timers/timerreference/timerfunctions/queryperformancefrequency.asp?frame=true">retrieves</A> the frequency of the high resolution performance counter and rejects any value above <CODE>INT_MAX</CODE> = 2,147,483,647:</P><PRE class=Code><SPAN style="COLOR: blue">if</SPAN> (!::QueryPerformanceFrequency((LARGE_INTEGER *)&amp;_freq) || <SPAN style="BACKGROUND-COLOR: yellow">_freq &gt; INT_MAX</SPAN>)
{
&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: green">// Counter not available</SPAN>
&nbsp;&nbsp;&nbsp; _freq = 0;
}
</PRE>
<P>Below are the command-line arguments I used with Msxsl and Saxon. The number after <CODE>-u</CODE> specifies the version of MSXML to use, <CODE>-o nul</CODE> redirects output to the NUL device, so that file input/output operations affect our measurements in a minimal way. The undocumented <CODE>-9</CODE> option forces Saxon to repeat the transform 9 times in a row, so that we obtain transformation time for the "warm" process. Unfortunately, the Msxsl utility does not provide a similar option, so for now MSXML 3.0/4.0 will be a little discriminated against. Both Saxon processors were run under Java™ 2 Runtime Environment version 1.4.2.</P><PRE class=Console>C:\XsltPerf&gt;<SPAN style="COLOR: yellow">msxsl.exe -t -o nul -u 3.0 Kasparov-Karpov.xml chess.xsl</SPAN>

C:\XsltPerf&gt;<SPAN style="COLOR: yellow">msxsl.exe -t -o nul -u 4.0 Kasparov-Karpov.xml chess.xsl</SPAN>

C:\XsltPerf&gt;<SPAN style="COLOR: yellow">java -jar saxon6.5.5\saxon.jar -t -o nul -9 Kasparov-Karpov.xml chess.xsl</SPAN>

C:\XsltPerf&gt;<SPAN style="COLOR: yellow">java -jar saxon8.7.3\saxon8.jar -t -o nul -9 Kasparov-Karpov.xml chess.xsl</SPAN>
</PRE>
<P>Finally, for <CODE>XslTransform</CODE> and <CODE>XslCompiledTransform</CODE> I used the XsltPerf utility, presented in my <A href="https://blogs.msdn.com/antosha/archive/2006/07/16/667221.aspx" mce_href="https://blogs.msdn.com/antosha/archive/2006/07/16/667221.aspx">previous post</A>. The System.Data.SqlXml assembly was NGen'd, though I doubt it could considerably affect performance in the "warm" case. As a separate step, I verified that all processors produce the correct output.</P>
<P>For the first test, let's try the Queens stylesheet I used in the previous post. To not force you to read it, I recall here that this <A href="https://www.datapower.com/xmldev/xsltmark.html" mce_href="https://www.datapower.com/xmldev/xsltmark.html">XSLTMark</A> benchmark stylesheet, developed by Oren Ben-Kiki, finds all the possible solutions to the problem of placing <I>N</I> queens on an <I>N</I>×<I>N</I> chess board without any queen attacking another. XSLTMark uses <I>N</I> = 6, and the issue I immediately encountered was that one run of this scenario was executed too fast to make measurements quite reliable. So I tweaked its input file, which originally looked as <CODE><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: maroon">BoardSize</SPAN><SPAN style="COLOR: blue">&gt;</SPAN>6<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: maroon">BoardSize</SPAN><SPAN style="COLOR: blue">&gt;</SPAN></CODE> to make the stylesheet solving the same problem 20 times:</P><PRE class=Code><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: maroon">Root</SPAN><SPAN style="COLOR: blue">&gt;</SPAN>
    <SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: maroon">BoardSize</SPAN><SPAN style="COLOR: blue">&gt;</SPAN>6<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: maroon">BoardSize</SPAN><SPAN style="COLOR: blue">&gt;</SPAN>
    ... <EM>18 identical lines skipped here</EM> ...
    <SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: maroon">BoardSize</SPAN><SPAN style="COLOR: blue">&gt;</SPAN>6<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: maroon">BoardSize</SPAN><SPAN style="COLOR: blue">&gt;</SPAN>
<SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: maroon">Root</SPAN><SPAN style="COLOR: blue">&gt;</SPAN>
</PRE>
<P>Below are results for my Intel<SUP>®</SUP> Xeon<SUP>®</SUP> 3GHz box. Since <CODE>XslCompiledTransform</CODE> performance is affected by JIT-compilation on first use, as I described in my <A href="https://blogs.msdn.com/antosha/archive/2006/07/16/667221.aspx" mce_href="https://blogs.msdn.com/antosha/archive/2006/07/16/667221.aspx">previous post</A>, I give execution times of the first <CODE>Transform</CODE> call for this processor in parentheses. For example, for this stylesheet the first <CODE>Transform</CODE> takes about 53 ms, and subsequent ones take about 34 ms.</P>
<DIV style="TEXT-ALIGN: center">
<TABLE class="" style="BORDER-RIGHT: #bbb 1px solid; BORDER-TOP: #bbb 1px solid; BACKGROUND: #eeeeee; BORDER-LEFT: #bbb 1px solid; BORDER-BOTTOM: #bbb 1px solid" cellSpacing=0 cellPadding=5 border=0>
<THEAD>
<TR>
<TH class="" colSpan=2>Queens</TH></TR></THEAD>
<TBODY>
<TR>
<TD class="" style="TEXT-ALIGN: right">XslTransform<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=296 bgColor=red>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>1480 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">MSXML 3.0 SP5<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=276 bgColor=red>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>1380 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">Saxon 8.7.3J<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=170 bgColor=orange>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>850 ms<!--1220 ms--></TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">Saxon 6.5.5<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=110 bgColor=orange>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>550 ms<!--800 ms--></TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">MSXML 4.0 SP2<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=30 bgColor=green>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>148 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">XslCompiledTransform<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=7 bgColor=green>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>34 ms (53 ms)</TD></TR></TBODY></TABLE></DIV>
<P>As you can see, MSXML 4.0 and <CODE>XslCompiledTransform</CODE> are much faster than other processors on this test; moreover, the latter is about 4 times faster than the former. I would like to note that the Queens stylesheet is rather artificial—it is an implementation of the <A href="https://en.wikipedia.org/wiki/Backtracking" mce_href="https://en.wikipedia.org/wiki/Backtracking">backtracking</A> algorithm in the language mainly oriented to deal with XML transformations. While it cannot be considered a real-world scenario, <CODE>XslCompiledTransform</CODE> performs really good even in that area. And if, in the past, performance issues might force you to implement similar helper functions in a general-purpose programming language, like C# or JScript, and call them using embedded scripts or extension objects technologies, now there is a greater chance you can implement those functions in XSLT itself and still have good performance.</P>
<P>For the following tests we take a couple of <A href="https://www.sarvega.com/xslt-benchmark.html" mce_href="https://www.sarvega.com/xslt-benchmark.html">Sarvega XSLT Benchmark</A> stylesheets, which represent real-world XSLT transforms. The <A href="https://www.renderx.com/chess.html" mce_href="https://www.RenderX.com/chess.html">Chess-FO</A> stylesheet, developed by Anton Dovgyallo from the Russian Academy of Sciences, reads the sequence of moves in a chess game and produces a set of chess board diagrams, representing every intermediate position as a graphical image in the <A href="https://en.wikipedia.org/wiki/XSL-FO" mce_href="https://en.wikipedia.org/wiki/XSL-FO">XSL-FO</A> format:</P>
<P style="TEXT-ALIGN: center"><IMG src="https://antosha.com/images/ChessBoard.gif" mce_src="https://antosha.com/images/ChessBoard.gif"></P>
<P style="FONT-WEIGHT: bold; TEXT-ALIGN: center">Kasparov–Karpov<BR>1990 World Championship Game</P>
<P>Again, MSXML 4.0 and <CODE>XslCompiledTransform</CODE> are several times faster than other processors. And if the first transformation for <CODE>XslCompiledTransform</CODE> takes 2 times longer than for MSXML 4.0 due to JIT-compilation, subsequent ones are 4 times faster.</P>
<DIV style="TEXT-ALIGN: center">
<TABLE class="" style="BORDER-RIGHT: #bbb 1px solid; BORDER-TOP: #bbb 1px solid; BACKGROUND: #eeeeee; BORDER-LEFT: #bbb 1px solid; BORDER-BOTTOM: #bbb 1px solid" cellSpacing=0 cellPadding=5 border=0>
<THEAD>
<TR>
<TH class="" colSpan=2>Chess-FO</TH></TR></THEAD>
<TBODY>
<TR>
<TD class="" style="TEXT-ALIGN: right">MSXML 3.0 SP5<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=235 bgColor=red>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>470 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">XslTransform<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=190 bgColor=red>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>380 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">Saxon 8.7.3J<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=150 bgColor=orange>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>300 ms<!--610 ms--></TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">Saxon 6.5.5<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=145 bgColor=orange>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>290 ms<!--516 ms--></TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">MSXML 4.0 SP2<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=26 bgColor=green>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>52 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">XslCompiledTransform<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=6 bgColor=green>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>13 ms (101 ms)</TD></TR></TBODY></TABLE></DIV>
<P>The DocBook-XHTML stylesheet, developed by Norman Walsh, transforms documents written in the <A href="https://en.wikipedia.org/wiki/Docbook" mce_href="https://en.wikipedia.org/wiki/Docbook">DocBook</A> format to XHTML. The input document used in Sarvega XSLT Benchmark is rather small—under 100 KB—and produces dozens of messages during its transformation. I had to redirect those messages to a file to minimize influence of <CODE>xsl:message</CODE> instructions on transformation time.</P>
<P><A class="" title=DocBookJitTime name=DocBookJitTime></A>DocBook-XHTML is a huge stylesheet with thousands of templates, global parameters and variables, and you can see how badly JIT-compilation affects the first stylesheet run in case of <CODE>XslCompiledTransform</CODE>: 1970 ms versus 60 ms for subsequent runs. It would be really nice to have the ability to pre-compile and "pre-JIT" stylesheets, so you would not pay this price again and again on each application run, but currently the .NET Framework 2.0 does not provide means for that.</P>
<DIV style="TEXT-ALIGN: center">
<TABLE class="" style="BORDER-RIGHT: #bbb 1px solid; BORDER-TOP: #bbb 1px solid; BACKGROUND: #eeeeee; BORDER-LEFT: #bbb 1px solid; BORDER-BOTTOM: #bbb 1px solid" cellSpacing=0 cellPadding=5 border=0>
<THEAD>
<TR>
<TH class="" colSpan=2>DocBook-XHTML</TH></TR></THEAD>
<TBODY>
<TR>
<TD class="" style="TEXT-ALIGN: right">MSXML 3.0 SP5<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="DISPLAY: inline; MARGIN: 0px; HEIGHT: 0.7em" width=260 bgColor=red>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>... 
<TABLE class="" style="DISPLAY: inline; MARGIN: 0px; HEIGHT: 0.7em" width=20 bgColor=red>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE><BR>2800 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">XslTransform<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=230 bgColor=red>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>460 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">Saxon 6.5.5<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=140 bgColor=orange>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>280 ms<!--672 ms--></TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">Saxon 8.7.3J<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=120 bgColor=orange>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>240 ms<!--812 ms--></TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">MSXML 4.0 SP2<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=70 bgColor=green>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>140 ms</TD></TR>
<TR>
<TD class="" style="TEXT-ALIGN: right">XslCompiledTransform<BR>&nbsp;</TD>
<TD class="">
<TABLE class="" style="MARGIN: 0px; HEIGHT: 0.7em" width=30 bgColor=green>
<TBODY>
<TR>
<TD class=""></TD></TR></TBODY></TABLE>60 ms (1970 ms)</TD></TR></TBODY></TABLE></DIV>
<P>One can make a couple of conclusions from the results above:</P>
<UL>
<LI>XSLT compilers steal a march on XSLT interpreters. While MSXML 4.0 is not a true compiler, the P-code it generates is close to the machine code, which allows it to surpass by far pure XSLT interpreters.</LI>
<LI><CODE>XslCompiledTransform</CODE> is a true XSLT compiler and may transform several times faster than MSXML 4.0. However, since the .NET Framework 2.0 currently does not allow you to save compiled stylesheets, you have to pay the compilation price on each application run.</LI></UL>
<P>Now it does not seem a coincidence that the last release of the Java platform, J2SE 5.0, <A href="https://java.sun.com/j2se/1.5.0/docs/guide/xml/jaxp/JAXP-Compatibility_150.html" mce_href="https://java.sun.com/j2se/1.5.0/docs/guide/xml/jaxp/JAXP-Compatibility_150.html">replaced</A> the Xalan interpreting processor with the XSLTC compiling processor as the default XSLT engine. And that Michael Kay, the creator of Saxon, is <A href="https://saxonica.blogharbor.com/blog/_archives/2006/7/24/2157486.html" mce_href="https://saxonica.blogharbor.com/blog/_archives/2006/7/24/2157486.html">experimenting</A> in the same direction. However, it is a very untrivial task to develop a compiler from an interpreter. As you remember, Microsoft had to discard the old interpreter code base and start from scratch twice—and their efforts led to creating swift and reliable <CODE>XslCompiledTransform</CODE> and MSXML 4.0 XSLT processors.</P>]]></content:encoded>
    </item>
    <item>
      <title>XslCompiledTransform Slower than XslTransform?</title>
      <link>https://docs.microsoft.com/archive/blogs/antosha/xslcompiledtransform-slower-than-xsltransform</link>
      <pubDate>Sun, 16 Jul 2006 10:40:00 GMT</pubDate>
      <dc:creator><![CDATA[antosha]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/antosha/2006/07/16/xslcompiledtransform-slower-than-xsltransform/</guid>
      <description><![CDATA[This post discusses:

Why XslCompiledTransform may be slower than XslTransform
How to reduce...]]></description>
      <content:encoded><![CDATA[<P>This post discusses:</P>
<UL>
<LI>Why <CODE>XslCompiledTransform</CODE> may be slower than <CODE>XslTransform</CODE></LI>
<LI>How to reduce start-up time if you use one of the managed XSLT processors</LI>
<LI>Why it is important to cache loaded <CODE>XslCompiledTransform</CODE> instances</LI></UL>
<P>The .NET Framework 2.0 provides a new <A href="https://msdn2.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform.aspx"><CODE>System.Xml.Xsl.XslCompiledTransform</CODE></A> XSLT processor class, which is intended to replace the obsoleted <CODE>XslTransform</CODE> class. One of the major differences between the two is that while the latter is an XSLT <A href="https://en.wikipedia.org/wiki/Interpreter_%28computing%29" mce_href="https://en.wikipedia.org/wiki/Interpreter_%28computing%29">interpreter</A>, the former is a real XSLT <A href="https://en.wikipedia.org/wiki/Compiler" mce_href="https://en.wikipedia.org/wiki/Compiler">compiler</A>, allowing significantly faster execution times. Does it mean <CODE>XslCompiledTransform</CODE> is always faster? Surprisingly, the answer is not that simple.</P>
<P>Let's write a simple test application that measures <CODE>Load</CODE> and <CODE>Transform</CODE> times for both <CODE>XslTransform</CODE> and <CODE>XslCompiledTransform</CODE> processors. Here is the most interesting part of the code, and the full source code is available in the attached file.</P><PRE class=Code><SPAN style="COLOR: blue">private</SPAN> <SPAN style="COLOR: blue">void</SPAN> TestXslCompiledTransform() {
&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: teal">XslCompiledTransform</SPAN> xslt = <SPAN style="COLOR: blue">null</SPAN>;

&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">for</SPAN> (<SPAN style="COLOR: blue">int</SPAN> i = 0; i &lt; numberOfIterations; i++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: teal">Stopwatch</SPAN> stopwatch = <SPAN style="COLOR: teal">Stopwatch</SPAN>.StartNew();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xslt = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: teal">XslCompiledTransform</SPAN>();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xslt.Load(xslFile);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stopwatch.Stop();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: teal">Console</SPAN>.WriteLine(<SPAN style="COLOR: maroon">"Load time: {0} ms"</SPAN>, FormatTime(stopwatch));
&nbsp;&nbsp;&nbsp; }

&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: teal">Console</SPAN>.WriteLine(<SPAN style="COLOR: maroon">"------------------------"</SPAN>);
&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: teal">XPathDocument</SPAN> doc = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: teal">XPathDocument</SPAN>(xmlFile);

&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: blue">for</SPAN> (<SPAN style="COLOR: blue">int</SPAN> i = 0; i &lt; numberOfIterations; i++) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: teal">Stopwatch</SPAN> stopwatch = <SPAN style="COLOR: teal">Stopwatch</SPAN>.StartNew();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xslt.Transform(doc, (<SPAN style="COLOR: teal">XsltArgumentList</SPAN>)<SPAN style="COLOR: blue">null</SPAN>, <SPAN style="COLOR: teal">XmlWriter</SPAN>.Create(<SPAN style="COLOR: teal">TextWriter</SPAN>.Null, xslt.OutputSettings));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stopwatch.Stop();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <SPAN style="COLOR: teal">Console</SPAN>.WriteLine(<SPAN style="COLOR: maroon">"Transform time: {0} ms"</SPAN>, FormatTime(stopwatch));
&nbsp;&nbsp;&nbsp; }
}
</PRE>
<P>Note that both <CODE>Load</CODE> and <CODE>Transform</CODE> are executed multiple times in a loop, and their times are measured separately. Also we pre-load the input document and output results of the transformation to <CODE>TextWriter.Null</CODE>, so that file input/output operations are not taken into account. (I accidentally forgot to pre-load the stylesheet in memory, however that did not make a noticeable difference on the results obtained below, because I ran XsltPerf with the same stylesheet multiple times, and the stylesheet file was sitting in the disk cache after the first run.) If you are new to the <CODE>XslCompiledTransform</CODE> class and wondering what <CODE>xslt.OutputSettings</CODE> is doing in this snippet, you may find the answer in Erik Saltwell's post "<A href="https://blogs.msdn.com/eriksalt/archive/2005/07/27/OutputSettings.aspx" mce_href="https://blogs.msdn.com/eriksalt/archive/2005/07/27/OutputSettings.aspx">What the heck is OutputSettings</A>".</P>
<P>The application allows you to specify filenames of the input document and the XSLT stylesheet, the number of iterations, and which XSLT processor to use:</P><PRE class=Console>C:\XsltPerf&gt;<SPAN style="COLOR: yellow">XsltPerf.exe /?</SPAN>
XSLT Load &amp; Transform Performance Test Utility
for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727

XsltPerf [/xt | /xct] [/i:&lt;n&gt;] &lt;xml-file&gt; &lt;xsl-file&gt;

Options:

/xt         Use XslTransform
/xct        Use XslCompiledTransform (default)
/i:&lt;n&gt;      Iterate n times (default is 5)</PRE>
<P>For testing purposes, we take one of <A href="https://www.datapower.com/xmldev/xsltmark.html" mce_href="https://www.datapower.com/xmldev/xsltmark.html">XSLTMark</A> benchmark stylesheets, namely queens.xsl, which finds all the possible solutions to the problem of placing <I>N</I> queens on an <I>N</I>×<I>N</I> chess board without any queen attacking another. XSLTMark uses <I>N</I> = 6, and so will we. Let's run the XsltPerf utility several times before taking readings to ensure the measurements take place on a "warm" machine:</P><PRE class=Console>C:\XsltPerf&gt;<SPAN style="COLOR: yellow">XsltPerf.exe /xt queens.xml queens.xsl</SPAN></PRE>
<P>The results for my Intel<SUP>®</SUP> Xeon<SUP>®</SUP> 3GHz box shows that the <EM>very</EM> first <CODE>Load</CODE> in a process is very slow for <CODE>XslTransform</CODE> and <EM>incredibly</EM> slow in case of <CODE>XslCompiledTransform</CODE>. The very first <CODE>Transform</CODE> is also significantly slower than subsequent ones. If you sum up the time for the first <CODE>Load</CODE> and the time for the first <CODE>Transform</CODE>, you'll get 239 ms for <CODE>XslTransform</CODE> versus 928 ms for <CODE>XslCompiledTransform</CODE>. In this particular scenario the new <CODE>XslCompiledTransform</CODE> class is almost 4 times slower!</P>
<DIV style="TEXT-ALIGN: center">
<TABLE class="" style="BACKGROUND: #eeeeee" cellSpacing=1 cellPadding=6 border=3>
<THEAD>
<TR>
<TH class="">XslTransform</TH>
<TH class="">XslCompiledTransform</TH></TR></THEAD>
<TBODY>
<TR>
<TD class=""><SPAN style="BACKGROUND-COLOR: yellow">Load time: 90.69 ms</SPAN><BR>Load time: 2.847 ms<BR>Load time: 1.841 ms<BR>Load time: 2.681 ms<BR>Load time: 1.891 ms<BR>
<HR style="MARGIN: 0px; COLOR: #000000">
<SPAN style="BACKGROUND-COLOR: yellow">Transform time: 148.0 ms</SPAN><BR>Transform time: 76.57 ms<BR>Transform time: 73.82 ms<BR>Transform time: 74.49 ms<BR>Transform time: 74.22 ms<BR></TD>
<TD class=""><SPAN style="BACKGROUND-COLOR: yellow">Load time: 882.2 ms</SPAN><BR>Load time: 4.582 ms<BR>Load time: 3.060 ms<BR>Load time: 3.119 ms<BR>Load time: 3.072 ms<BR>
<HR style="MARGIN: 0px; COLOR: #000000">
<SPAN style="BACKGROUND-COLOR: yellow">Transform time: 45.31 ms</SPAN><BR>Transform time: 2.027 ms<BR>Transform time: 2.027 ms<BR>Transform time: 1.962 ms<BR>Transform time: 1.977 ms<BR></TD></TR></TBODY></TABLE></DIV>
<P>So what the hell happens on the first call? In the .NET Framework 2.0 implementations of <CODE>XslTransform</CODE> and <CODE>XslCompiledTransform</CODE> were moved to a helper System.Data.SqlXml assembly in order to reduce the size of System.Xml. And apparently that helper assembly is not NGen'd by default, so its methods are JIT-compiled on first use:</P><PRE class=Console>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727&gt;<SPAN style="COLOR: yellow">ngen display System.Data.SqlXml</SPAN>
Microsoft (R) CLR Native Image Generator - Version 2.0.50727.42
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.
Error: The specified assembly is not installed.
</PRE>
<P>(If you don't know what <A href="https://msdn2.microsoft.com/en-us/library/6t9t5wcf.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/6t9t5wcf.aspx">NGen</A> or <A href="https://msdn2.microsoft.com/en-us/library/ht8ecch6.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/ht8ecch6.aspx">JIT</A> is, I highly recommend reading the "<A href="https://msdn.microsoft.com/msdnmag/issues/05/04/NGen/" mce_href="https://msdn.microsoft.com/msdnmag/issues/05/04/NGen/">NGen Revs Up Your Performance with Powerful New Features</A>" article.) JIT-compilation affects the first <CODE>XslCompiledTransform.Load</CODE> call much more significantly comparing to <CODE>XslTransform.Load</CODE>, because the compiler uses substantially more complex code than the interpreter.</P>
<P>Considering that other key .NET Framework assemblies are NGen'd, missing of System.Data.SqlXml in the native image cache may be a simple oversight on the part of .NET Framework installer. Let's generate a native image for the System.Data.SqlXml assembly:</P><PRE class=Console>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727&gt;<SPAN style="COLOR: yellow">ngen install "System.Data.SqlXml, Version=2.0.0.0,
 Culture=neutral, PublicKeyToken=b77a5c561934e089" /nologo</SPAN>
Installing assembly System.Data.SqlXml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Compiling 1 assembly:
    Compiling assembly System.Data.SqlXml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ...
System.Data.SqlXml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</PRE>
<P>and run our test application again. I have copied the previous results to make it's easier for you to compare:</P>
<DIV style="TEXT-ALIGN: center">
<TABLE class="" style="BACKGROUND: #eeeeee" cellSpacing=1 cellPadding=6 border=3>
<THEAD>
<TR>
<TH class="">XslTransform</TH>
<TH class="">XslCompiledTransform</TH></TR></THEAD>
<TBODY>
<TR>
<TH class="" colSpan=2>System.Data.SqlXml is not NGen'd</TH></TR>
<TR>
<TD class=""><SPAN style="BACKGROUND-COLOR: yellow">Load time: 90.69 ms</SPAN><BR>Load time: 2.847 ms<BR>Load time: 1.841 ms<BR>Load time: 2.681 ms<BR>Load time: 1.891 ms<BR>
<HR style="MARGIN: 0px; COLOR: #000000">
<SPAN style="BACKGROUND-COLOR: yellow">Transform time: 148.0 ms</SPAN><BR>Transform time: 76.57 ms<BR>Transform time: 73.82 ms<BR>Transform time: 74.49 ms<BR>Transform time: 74.22 ms<BR></TD>
<TD class=""><SPAN style="BACKGROUND-COLOR: yellow">Load time: 882.2 ms</SPAN><BR>Load time: 4.582 ms<BR>Load time: 3.060 ms<BR>Load time: 3.119 ms<BR>Load time: 3.072 ms<BR>
<HR style="MARGIN: 0px; COLOR: #000000">
<SPAN style="BACKGROUND-COLOR: yellow">Transform time: 45.31 ms</SPAN><BR>Transform time: 2.027 ms<BR>Transform time: 2.027 ms<BR>Transform time: 1.962 ms<BR>Transform time: 1.977 ms<BR></TD></TR>
<TR>
<TH class="" colSpan=2>System.Data.SqlXml is NGen'd</TH></TR>
<TR>
<TD class=""><SPAN style="BACKGROUND-COLOR: yellow">Load time: 19.27 ms</SPAN><BR>Load time: 2.894 ms<BR>Load time: 1.895 ms<BR>Load time: 2.753 ms<BR>Load time: 1.911 ms<BR>
<HR style="MARGIN: 0px; COLOR: #000000">
<SPAN style="BACKGROUND-COLOR: yellow">Transform time: 77.22 ms</SPAN><BR>Transform time: 75.93 ms<BR>Transform time: 73.56 ms<BR>Transform time: 74.49 ms<BR>Transform time: 73.78 ms<BR></TD>
<TD class=""><SPAN style="BACKGROUND-COLOR: yellow">Load time: 58.57 ms</SPAN><BR>Load time: 4.862 ms<BR>Load time: 3.238 ms<BR>Load time: 3.280 ms<BR>Load time: 3.272 ms<BR>
<HR style="MARGIN: 0px; COLOR: #000000">
<SPAN style="BACKGROUND-COLOR: yellow">Transform time: 15.23 ms</SPAN><BR>Transform time: 1.918 ms<BR>Transform time: 1.921 ms<BR>Transform time: 1.949 ms<BR>Transform time: 1.926 ms<BR></TD></TR></TBODY></TABLE></DIV>
<P>As you can see, the first <CODE>Load</CODE> call became much faster, though it still consumes some extra time to load the helper assembly into process memory and initialize all needed classes. Now <CODE>XslCompiledTransform.Load</CODE> is "only" 3 times slower than <CODE>XslTransform.Load</CODE>; however, this is expected — compiling, in general, is more expensive than the interpreter preparation work. It is the price you have to pay for faster execution: <CODE>XslCompiledTransform.Transform</CODE>, except the first call, is about <STRONG>40 times</STRONG> faster!</P>
<P>If you look at new <CODE>Transform</CODE> times, you may note that the difference between the first and subsequent calls to <CODE>XslTransform.Transform</CODE>, thanks to NGen'ing, almost disappeared. But why is the first call to <CODE>XslCompiledTransform.Transform</CODE> still <STRONG>8 times</STRONG> slower?! Here we need to recall that <CODE>XslCompiledTransform</CODE> compiles the stylesheet to MSIL methods. All those generated methods are subject to JIT-compiling on first use. While JIT-compilation is relatively expensive, its cost is usually amortized over several executions of compiled methods. For example, in our scenario the first <CODE>XslCompiledTransform.Transform</CODE> call is still faster than <CODE>XslTransform.Transform</CODE> one. However, in case of very simple stylesheets like <CODE><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: teal">xsl:template</SPAN><SPAN style="COLOR: blue"> </SPAN><SPAN style="COLOR: red">match</SPAN><SPAN style="COLOR: blue">=</SPAN>"<SPAN style="COLOR: blue">/</SPAN>"<SPAN style="COLOR: blue">&gt;&lt;</SPAN><SPAN style="COLOR: maroon">foo</SPAN><SPAN style="COLOR: blue">/&gt;&lt;/</SPAN><SPAN style="COLOR: teal">xsl:template</SPAN><SPAN style="COLOR: blue">&gt;</SPAN></CODE> the first <CODE>XslCompiledTransform.Transform</CODE> call may perform several times worse.</P>
<P>I'd like to emphasize the principal difference between the "first <CODE>Load</CODE>" issue (relates to both <CODE>XslTransform</CODE> and <CODE>XslCompiledTransform</CODE>) and the "first <CODE>Transform</CODE>" issue (relates to <CODE>XslCompiledTransform</CODE> only). In the former case, the first <CODE>Load</CODE> per <EM>process</EM><SUP><A id=footnoteref1 href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=5780&amp;postid=667221#footnote1" mce_href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=5780&amp;postid=667221#footnote1">1</A></SUP> is affected. In the latter one, the first <CODE>Transform</CODE> per <EM>loaded stylesheet</EM> is affected. If you load a different stylesheet or even reload the same stylesheet into the same <CODE>XslCompiledTransform</CODE> instance, a new bunch of MSIL methods will be generated and JIT-compiled on their first use.</P>
<DIV style="PADDING-LEFT: 2em">
<P><SUP><A id=footnote1 href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=5780&amp;postid=667221#footnoteref1" mce_href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=5780&amp;postid=667221#footnoteref1">1</A></SUP> Or per <CODE>AppDomain</CODE> in case of multi-<CODE>AppDomain</CODE> applications. For more information on sharing native images across <CODE>AppDomain</CODE>s, you may read <A href="https://msdn.microsoft.com/msdnmag/issues/06/05/CLRInsideOut/#S6" mce_href="https://msdn.microsoft.com/msdnmag/issues/06/05/CLRInsideOut/#S6">this</A> and <A href="https://blogs.msdn.com/junfeng/archive/2004/08/05/208375.aspx" mce_href="https://blogs.msdn.com/junfeng/archive/2004/08/05/208375.aspx">this</A>.</P></DIV>
<P>Let's make some conclusions of this little experiment:</P>
<UL>
<LI>If you are using one of the .NET Framework 2.0 XSLT processors (<CODE>XslTransform</CODE> or <CODE>XslCompiledTransform</CODE>), NGen'ing the System.Data.SqlXml assembly may improve the application start-up time. This does not relate to the .NET Framework 1.1, which has the <CODE>XslTransform</CODE> implementation NGen'd by default.</LI>
<LI><CODE>XslCompiledTransform.Load</CODE> is slower than <CODE>XslTransform.Load</CODE>, though it's unlikely to become a concern.</LI>
<LI><CODE>XslCompiledTransform.Transform</CODE> performance may degrade by several times due to JIT-compilation. JIT-compilation happens on first use of a stylesheet template, and in many cases it would be the very first <CODE>XslCompiledTransform.Transform</CODE> call for the given stylesheet loaded into an <CODE>XslCompiledTransform</CODE> instance that is affected the most.</LI>
<LI>While <CODE>XslCompiledTransform</CODE> is a best choice for the "one <CODE>Load</CODE>, many <CODE>Transform</CODE>s" scenario, it may be slow for the "one <CODE>Load</CODE>, one <CODE>Transform</CODE>" scenario, especially for very simple XML/XSLT files and when stylesheet templates are executed only few times. In those cases <CODE>XslTransform</CODE> may be faster.</LI>
<LI>It is important, especially for server applications, to cache an <CODE>XslCompiledTransform</CODE> instance if the same stylesheet is likely to be executed again.</LI></UL>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/00/66/72/21/XsltPerf.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-00-66-72-21/XsltPerf.zip">XsltPerf.zip</a></p>]]></content:encoded>
    </item>
  </channel>
</rss>