SAXONICA

Saxon Documentation
Full Contents
About Saxon
Changes in this Release
| Version 8.7 (2006-02-24)
| Version 8.6.1 (24 November 2005)
| Version 8.6 (3 November 2005)
| Version 8.5.1 (26 August 2005)
» | Version 8.5 (2 August 2005)
| Version 8.4 (4 April 2005)
| Version 8.3 (11 February 2005)
| Version 8.2 (21 December 2004)
| Version 8.1.1 (8 October 2004)
| Version 8.1 (24 September 2004)
| Version 8.0 (1 June 2004)
Conditions of Use
Using XSLT 2.0
Using XQuery
Handling Source Documents
XML Schema Processing
The XPath API
Saxon on .NET
Extensibility
Saxon Extensions
Sample Saxon Applications
The Saxon SQL Extension
XSLT Elements
XPath 2.0 Expression Syntax
Function Library
Standards Conformance

# Internal Changes

There has been a change to the TinyTree structure. When a node has a very large number of siblings, finding the parent node from one of the siblings could involve a long search. The search was only necessary in cases where the child was found without remembering the parent - for example, when it was found via the descendant axis. The result was that for trees with a large fan-out (typically XML documents representing relational database tables) a few XPath expressions could experience very poor performance. This problem has been solved by inserting parent pointers into the tree. These are not added to every node, because it's important to save space in the TinyTree, but instead one parent pointer is added for every ten siblings. Many trees rarely see a fan-out as high as ten, in which case these pointers will not appear at all. Note that the parent pointers are counted as extra nodes in the TinyTree statistics.

Another change made to the TinyTree is that it now contains a boolean flag indicating whether the tree contains any namespace nodes (other than the XML namespace). This reduces the cost of operations that copy an element node with all its namespaces.

When delayed evaluation is used for an expression (typically for a local variable), the context that the expression depends on is saved for use when the expression is eventually evaluated. Saxon now saves only those local variables that the expression actually references, whereas it previously saved the whole stack frame. This change has several benefits. Although the cost of doing the copying is small, not making copies of variables means that values can be discarded more quickly from memory by the garbage collector. Also, Saxon has an algorithm that prevents long chains of unevaluated expressions building up, especially during recursive processing: this algorithm is now more sensitive, as it only recognizes a chain where there is a genuine dependency. This prevents unnecessary early evaluation of expressions, which costs time and uses memory. In particular, there were situations where a local variable is declared in a loop, and each time round the loop the stack frame is saved, including the previous value of the same local variable, and so on.

Operations that atomize a sequence of nodes and expect the result to be a sequence containing zero or one atomic values (arithmetic is a typical example) have been speeded up by combining the operations of atomization and cardinality checking, and by providing a new method `atomize()` on the `NodeInfo` interface which (unlike the existing `getTypedValue()` method) returns the actual value rather than an iterator. This removes several iterators from the evaluation pipeline, thus reducing overheads.

When taking input from a DOMSource, Saxon now tests to see whether the supplied document supports DOM level 3 methods, and if it does so, it uses the DOM methods `isSameNode()` and `compareDocumentPosition()` when sorting nodes into document order. These have the potential to be more efficient than Saxon's algorithms for comparing document order (though it depends on the implementation, of course).

The `RegexIterator` class, supporting `xsl:analyze-string` and the `saxon:analyze-string()` extension function, has been rewritten to take advantage of the `SequenceIterator` redesign introduced some while ago, which means that it no longer needs to perform lookahead. This greatly simplifies the design and improves performance. In the course of this simplification, it was found that the `last()` function was not working on this iterator.

Where the values of constructed text nodes and attributes are known at compile time, Saxon now analyzes the value at compile time; if the value consists of ASCII characters with no special characters that might need escaping, the value is marked as such to save unnecessary work at serialization time. Previously this optimization was done only for attribute values of literal result elements in XSLT. Whitespace text nodes generated as a result of the `indent="yes"` option also benefit from this optimization.

The `Expression.analyze()` method, previously used to perform type checking and optimization on expressions in the abstract expression tree, has been split into two methods: `typeCheck()` and `optimize()`. This means that this phase of processing has been split into two phases. This has a number of benefits: (a) the optimize() phase is optional, and can be omitted in contexts such as `saxon:evaluate()` or when debugging; (b) it removes the problem that `analyze()` was being executed twice in XSLT, once at the XPath expression level and once at the level of a template or function (now, `typeCheck()` is called once for each XPath expression, and `optimize()` is called at the template or function level), and (c) it enables the optimization of a parent expression to perform tree rewrites after the type-checking of subordinate expressions, but before they are themselves optimized, which sometimes makes it easier to recognize the subexpressions that are amenable to optimization.

The way the XSLT `current()` function works has changed. Previously, this was quietly moved to the top level of an XPath expression by virtue of the fact that expressions that don't depend on a loop variable are moved outside the loop. The problem was that as optimization increasingly happens at the level of a template or function, it was difficult to ensure that the call was moved to the right place. There is now an explicit rewrite that replaces the call on `current()` with a reference to a system-generated variable at the level of an XPath expression as written in XSLT. During this rewrite I discovered bug 1200164, which required a fairly substantial redesign of the way `current()` works within a pattern.

A set of nested `let` expressions is now evaluated iteratively rather than by recursion, reducing the use of Java stack space and increasing the scope for the garbage collector to free heap memory. This affects XSLT as well as XQuery, because a sequence of local `xsl:variable` instructions is compiled into a nested set of `let` expressions. In 8.4 there was a restriction that tail call optimization was not invoked on an XSLT template whose body was a `let` expression (in source terms, a sequence of instructions starting with `xsl:variable`): this restriction has been removed.

Runtime type checking can now be performed within the push pipeline: this typically arises when an "as" attribute is used on `xsl:template`. Previously this resulted in the value of the template being physically constructed in memory, and then checked against the type. This led to a lot of unnecessary use of memory and copying of intermediate results. The results of the template are now checked on-the-fly. As well as improving performance, this also means that the error messages can be more precise about the location of the code that generated the incorrect content.

Next