System Programming Interfaces

The behavior of configuration.buildDocument() has changed for cases where the supplied Source object is a tree. In particular, if it is a DOMSource then the DOM Document node will normally be wrapped in a Saxon wrapper object rather than being copied to a TinyTree. This has the effect of reinstating the pre-8.9 behaviour of methods in the XPath API that are given a DOMSource as an argument; the XPath expressions will now return nodes in the original DOM tree rather than copies of these nodes.

Support for DOM Level 2 implementations has been reinstated; however Saxon no longer attempts to detect whether the DOM supports level 3 interfaces; instead, when a Level 2 DOM implementation is used, the configuration setting config.setDOMLevel(2) must be used. (Saxon now has compile-time references to DOM level 3 methods, but will not call such methods if this configuration setting is in force.)

The class StaticQueryContext has been split into two: user-facing methods used to initialize the context for a query are still in StaticQueryContext, but methods intended for system use, which update the context as declarations in the query prolog are parsed, have been moved to a new class QueryModule. The class StaticQueryContext no longer implements the StaticContext interface.

As part of the above change, some methods on StaticQueryContext have been dropped. This notably includes the method declareVariable() which never worked in a satisfactory way because the variable was not reusable across multiple queries. External variables should always be declared from the query prolog.

A new factory method Configuration.makeConfiguration() is available. This creates a schema-aware configuration if Saxon-SA is installed and licensed, otherwise it creates a non-schema-aware configuration. This option is useful for applications that want to take advantage of the enhanced Saxon-SA optimizer in cases where it is available, but do not otherwise depend on Saxon-SA functionality.

A new method on Configuration is introduced to copy a Configuration. The main motivation for this is to eliminate the high cost of repeatedly checking the Saxon-SA license key in applications that create many separate Configurations.

The rule that all documents used within a single query, transformation, or XPath expression must be built using the same Configuration has been relaxed slightly, so the requirement is only that they must be "compatible" Configurations, which means in practice that they must use the same NamePool and DocumentNumberAllocator. Although the rule has been relaxed slightly, it is also now enforced on a number of interfaces where previously no checking took place (which could lead to unpredictable failures later). This applies in particular to XPath APIs.

A new option is available in the Configuration to indicate that calls to the doc() or document() functions with constant string arguments should be evaluated when a query or stylesheet is compiled, rather than at run-time. This option is intended for use when a reference or lookup document is used by all queries and transformations. Using this option has a number of effects: (a) the URI is resolved using the compile-time URIResolver rather than the run-time URIResolver; (b) the document is loaded into a document pool held by the Configuration, whose memory is released only when the Configuration itself ceases to exist; (c) all queries and transformations using this document share the same copy; (d) any updates to the document that occur between compile-time and run-time have no effect. The option is selected by using Configuration.setConfigurationProperty()\ or TransformerFactory.setAttribute() with the property name FeatureKeys.PRE_EVALUATE_DOC_FUNCTION. This option is not available from the command line because it has no useful effect with a single-shot compile-and-run interface.

A convenience method QueryResult.serialize(NodeInfo node) has been provided, allowing a node to be serialized as XML; the result is returned as a String.

There is also a convenience method Navigator.getAttributeValue(NodeInfo node, String uri, String localName) making it easier for Java applications to get an attribute of an element.

In the NodeInfo interface, the rules for the copy() method have changed so that when an element is copied, its namespaces must be output without duplicates (or without a declaration being cancelled by an undeclaration). The method no longer relies on the recipient removing such duplicates.

The method NodeInfo#sendNamespaceDeclarations has been deleted.

The class NameTest has a new constructor taking a URI and local name as strings, making it easier to construct a NameTest for use in calls to iterateAxis(). In addition, the abstract class NodeTest now has only one abstract method, making it easier to write a user-defined implementation of NodeTest for filtering the nodes returned by iterateAxis().

Methods that construct or convert atomic values no longer return ValidationErrorValue in the event of a failure. There were a couple of problems with this mechanism: although it was designed to eliminate the costs of throwing an exception, it failed to take into account the cost of creating the exception before throwing it, which is surprisingly expensive as it involves capturing a stack trace. Secondly, the mechanism wasn't type safe as it didn't force callers to check the return value for an error. These methods (and a number of others) now return a ConversionResult which is essentially a union type of AtomicValue and ValidationFailure. Code calling these methods therefore has to consciously cast the result to AtomicValue, preferably after checking that the result is not a ValidationFailure.

The two exception classes StaticError and DynamicError are no longer used: instead, their common base class XPathExpression is now a concrete class and is used to represent both static and dynamic errors. It includes a field to distinguish the two cases, though in fact there is very little code that cares about the difference (the only time the difference is significant is when dynamic errors occur during early compile-time evaluation of constant subexpressions). Any application code that contains a catch for StaticError or DynamicError should be changed to catch XPathException instead. Since nearly all API methods declared "throws XPathException" already, this is unlikely to be a major issue.

There has been some tidying up of methods on the AtomicValue class, especially methods for converting values between types and for setting the type label.