First off, it's worth pointing out the obvious difference. XmlPrime is an XSLT 2.0 processor, whereas XslCompiledTransform only supports XSLT 1.0. This means we can only compare the two processors executing XSLT 1.0 stylesheets, which requires XmlPrime to operate in "backwards-compatiblilty" mode, as defined by the XSLT 2.0 specification. Operating in this mode means that we are not on a level playing field.
Numeric operations
In XSLT 1.0, all numbers are double-precision floating point. In XSLT 2.0, numbers may be integers, decimals or floating point numbers. To meet the conformance requirements of XSLT 2.0, we use System.Decimal to represent both integer and decimal types. Mathematical operations can therefore be a little slower than using System.Double. For a fairer comparison, we could update the XSLT 1.0 stylesheet to XSLT 2.0 and ensure that all numeric literals are written as xs:double values.String operations
The implementation of string operations in XslCompiledTransform is wrong. Just try<xsl:value-of select="substring('💩', 1, 1)" />
The input is a string with a single unicode codepoint. This string is represented by a System.String instance of length two. The string consists of the two System.Char values which form the surrogate pair
The correct response for the above code is to output 💩 to the result document. Instead, XslCopmiledTransform outputs half of the surrogate pair. I suspect this is a case where performance outweights correctness. The string handling functions such as string-length, substring-before, substring-after and substring are all considerably simpler if yone ignores the requirements of the specification.
Access to Internals
It is most frustrating when you discover a really useful method or property of a class, only to discover that it is internal. One such case is the UniqueId property of XPathNavigator. This property is exactly what you would want to call to implement the fn:generate-id function efficiently. However, because it is internal, it is just out of reach (without doing something nasty).Type Inference
Suppose an XSLT 1.0 stylesheet contains the code<xsl:template name="add">
<xsl:param name="a" />
<xsl:param name="b" />
<xsl:value-of select="$a + $b" />
</xsl:template>
The compiler can't be sure what will be supplied for parameters a, and b. We might expect them to be numeric, but the caller could equally well pass in a node set and a boolean value. The clever compiler might check all usages of template add and discover that it is always called with a numeric value, thus avoiding any runtime checks.
XSLT 2.0 permits a stylesheet to be invoked by specifying an initial template. In that case, we don't have a "closed world" over which to run a static analysis. That is, we can't determine statically that add will always be supplied with numeric values. We could of course compile a specialized version of this template. This is something XmlPrime may do in the future.
Final Thoughts
In our benchmarking, we've seen cases where XmlPrime will outpace XslCompiledTransform on XSLT 1.0 stylesheets. There are also cases where XslCompiledTransform is a clear winner, and this is due at least in part to the differneces discussed above. When time permits, it would be interesting to convert some of the XSLT 1.0 benchmarks to XSLT 2.0 with an eye to extracting the best possible performance from an XSLT 2.0 processor.As ever, the advice is to measure performance for your use case and put a little effort into updating stylesheets where needed.
No comments:
Post a Comment