Release of Saxon 9.9
September 29, 2018
Submitted by Michael Kay via xml-dev.
Saxon 9.9 is now available, from the usual locations - http://www.saxonica.com/download/java.xml.
Specifically, Saxon-HE, Saxon-PE, and Saxon-EE are available for the Java platform. The .NET version will follow.
Saxon 9.9 requires Java 8.
Full details are available in the change log at http://www.saxonica.com/documentation/index.html#!changes , but here are the main highlights:
(1) There's a significant extension of the s9api interface to provide XDM tree navigation. Under the hood, this takes advantage of Java 8 streams. As an alternative to using XPath expressions such as
XdmValue selectedBooks = xpath.evaluate("//book[author='" + key + "']", doc);
you can now write
doc.select(descendant("book").where(eq(child("author"), key)).asXdmValue();
There's a usability benefit because you're only using one language (Java) rather than two (Java+XPath), and there's a performance benefit because it cuts out the expensive XPath parsing stage. It also reduces the risk of injection attacks, and is likely to detect more programming errors at compile time. To make this work, we're now requiring a baseline of Java 8.
(2) Tuple types extend the XPath type system to provide better type checking of complex data structures. If you're representing employee data as a map, then instead of declaring it as map(xs:string, item()*), you can now declare it as tuple(empNr: xs:string, dob: xs:date, name: element(personalName)). The result is more readable code, better type checking (meaning faster debugging), and better performance. The extension has been implemented in such a way that it can be used without compromising the portability of your code to other XSLT 3.0 processors.
(3) Arrays, like maps, now have an internal implementation that means updates to individual entries in the array don't require the whole array to be copied, giving substantial performance improvements for applications that use arrays heavily.
(4) Improvements have been implemented to the TinyTree data structure to further reduce memory usage, and to enable zero-cost copying of subtrees from one tree to another in the course of a transformation.
(5) A number of powerful new extension instructions and functions are provided to enable easier query and update of the trees of maps and arrays that typically arise when processing JSON input. For example, the instruction <saxon:deep-update root="json-doc('empData.json')" select="?*[?customer='Jones']?orders" action="array:append($order)"/> reads and parses a JSON file, adds a new order for a selected customer, and returns a data structure representing the modified data set, which can then be serialized using the JSON output method.
(6) Streamed accumulators, as defined in the XSLT 3.0 Recommendation, are extended with a new feature: by annotating an accumulator rule with the attribute saxon:capture="yes", an entire element from the source document can be captured as the value of the accumulator. For example this can be used to capture the header section at the start of a document and make it available for reference while the rest of the document is processed using pure streaming.
(7) The updating primitives of the XQuery Update specification are now available for use in XSLT via Saxon-defined extension instructions. These make many simple updates (such as "delete all comments") easier to express and faster in execution, without sacrificing the declarative nature of the XSLT language. For a future release we are thinking about new data structures that make such updates very efficient, avoiding the need to copy all the data in the source document that has not changed.
(8) The XPath lookup operator "?" has been exploited to provide easier call-out from XSLT and XQuery to Java code. For example, if the variable $connection holds a SQL database connection obtained using the sql:connect() extension function, then the expression $connection?isClosed() calls the Java method isClosed defined on the underlying connection object.
(9) The ability for an XSLT stylesheet to produce "raw" output (for example, a sequence of integers rather than an XML document), as envisaged in the XSLT 3.0 specification, is now much better supported in the Saxon API. A new RawDestination< is available to define the destination of a transformation. Internally, there has been a significant tidying-up of the interface between the transformation engine and a destination such as a Serializer.
(10) There have been further improvements to diagnostics on type errors. This applies especially when passing complex data structures between templates and functions using maps. In general, instead of telling you that the expected type was X but the supplied value V was an instance of Y, the message now tells you in what way V fails to conform to the type X: for example, if X is map{xs:string, node()} and V contains an entry whose key is of type xs:untypedAtomic, then the error message in 9.8 would tell you that V is an instance of map{xs:anyAtomicType, node()}, while 9.9 will tell you that V is not an instance of map{xs:string, node()} because it contains a key whose type is xs:untypedAtomic and whose value is (say) "Idaho".