Extensibility mechanisms
Saxon has long provided the ability to have an Item that wraps
an external Java or .NET object, which can be supplied in arguments to extension function
calls or used in the response from an extension function calls. In the past, such values
have appeared in the type hierarchy under "atomic value", that is, as a peer of types
such as xs:boolean
and xs:string
. This has changed so they
are no long atomic values, instead forming a fourth kind of item alongside nodes,
atomic values, and function items.
The string value and typed value of an external object are the same; they are the
xs:string
value that results from calling its toString()
method.
The handling of extension items that wrap a Java null
has
been tidied up. When a Java extension function returns null, this is mapped to
an XDM empty sequence, not to an extension item that wraps null. When an empty
sequence is supplied to a Java extension function that expects an Object, the
value null will be passed to the Java method. Extension items are therefore no longer allowed to
wrap a Java null.
With reflexive extension functions, the handling of Java arrays has been improved; the component type of the array is now considered when deciding which of several overloaded methods is the best fit.
With reflexive extension functions, if there are two methods where one
expects a String
and the other a CharSequence
, the one expecting a CharSequence
is now preferred. Previously the function call was rejected as ambiguous.
Although there is no particular reason for choosing one rather than the other,
it's likely that both methods will have the same effect, so choosing one
arbitrarily is better than reporting an error.
With reflexive extension functions, if there are two methods of the right name and arity, the decision which to use is now postponed until after type checking has been done. This is particularly useful when arguments are supplied in the form of variable references. Previously the decision was postponed only if the early analysis showed both methods as equally preferred; now it is always postponed.
When a constructor is called the code now does what the documentation has always
said: a wrapped external object is returned with no conversion. So for example
Date:new()
will return a wrapped java.util.Date
object rather than
an instance of xs:dateTime
, and HashMap:new()
will return a wrapped
HashMap
rather than an XPath map. The code also avoids doing conversions other
than object unwrapping for the first argument of a call to an instance method.
When a reflexive extension function throws an exception, the exception details
are now captured in an error that can be caught using the try/catch capabilities
in XSLT 3.0 and XQuery 3.0. In particular, the error code is a QName whose namespace
URI is "http://saxon.sf.net/java-type
and whose local name is the
class name of the exception type, for example java.net.URISyntaxException
.
It is now possible to use the reflexive call mechanism to call instance-level methods of the implementation classes for XDM values. For example, the following gets the current Julian instant:
<xsl:value-of select="d:toJulianInstant(current-dateTime())" xmlns:d="java:net.sf.saxon.value.DateTimeValue"/>When an instance of java.util.Map
is passed as a parameter to a stylesheet
or query, then by default it is accessible within the stylesheet or query as an XPath 3.0 map
object. However, if the parameter is declared with a required type of jt:java.util.Map
,
then it will instead be retained as an external object wrapping the java.util.Map
,
which means for example that (with the usual caveats and disclaimers) it is updateable by
calling its put()
method as an extension function.