Calling Static Methods in a .NET Class
Static methods can be called directly. The localname of the function must
match the name of a public static method in this class. The names match if they contain the
same characters, excluding hyphens and forcing any character that follows a hyphen to
upper-case. For example the XPath function call To-string()
matches the .NET
method ToString()
; but the function call can also be written as
ToString()
if you prefer.
If there are several methods in the class that match the localname, and that have the
correct number of arguments, then the system attempts to find the one that is the best fit
to the types of the supplied arguments: for example if the call is f(1,2)
then
a method with two int
arguments will be preferred to one with two
float
arguments. The rules for deciding between methods are quite complex.
Essentially, for each candidate method, Saxon calculates the "distance" between the types of
the supplied arguments and the .NET class of the corresponding argument in the method's
signature, using a set of tables. For example, the distance between the XPath
data type xs:integer
and the .NET type long
is very small, while
the distance between an XPath xs:integer
and a .NET bool
is much
larger. If there is one candidate method where the distances of all arguments are
less-than-or-equal-to the distances computed for other candidate methods, and the distance
of at least one argument is smaller, then that method is chosen.
If there are several methods with the same name and the correct number of arguments, but none is preferable to the others under these rules, an error is reported: the message indicates that there is more than one method that matches the function call.
This binding is carried out statically, using the static types of the supplied arguments,
not the dynamic types obtained when the arguments are evaluated. If there is insufficient
static type information to distinguish the candidate methods, an error is reported. You can
supply additional type information using the treat as
expression, or by
casting. Often it is enough simply to declare the types of the variables used as arguments
to the function call. Note however that if the argument can be evaluated at compile time,
then the type of the actual value will be used in preference to the declared type.
This is particularly relevant if the argument evaluates to an empty sequence.
If you need to invoke an overloaded method in this way, use an argument expression
that cannot be evaluated at compile time.
For example (in XSLT):
<xsl:value-of select="math:Sqrt($arg)" xmlns:math="clitype:System.Math"/>This will invoke the static method System.Math#Sqrt()
, applying it to the
value of the variable $arg
, and copying the value of the square root of
$arg
to the result tree. The value of $arg must be convertible to a double
under the same rules as for a native XPath function call.
Similarly (in XQuery):
<a xmlns:double="type:System.Double"/> {double:MaxValue()} </a>This will output the value of the static field System.Double#MaxValue
. (In
practice, it is better to declare the namespace in the query prolog, or predeclare it using
the API, because it will then not be copied to the result tree.)
A static method called as an extension function may have an extra first argument of type net.sf.saxon.expr.XPathContext.
This argument is not supplied by the calling XPath or XQuery code, but by Saxon itself. The
XPathContext
object provides methods to access many internal Saxon resources,
the most useful being getContextItem()
which returns the context item from the
dynamic context. The class net.sf.saxon.expr.XPathContext
is in the assembly
saxon-he-10.#.dll
, and the module containing the code of the extension function will
therefore need to contain a reference to that DLL. The class itself is written in Java, and
is documented in the Javadoc documentation. The XPathContext
object is
available with static or instance-level methods, but not with constructors.
The following example shows a function that obtains the host language from the Saxon evaluation context:
public static string HostLanguage(net.sf.saxon.expr.XPathContext context) { int lang = context.getController().getExecutable().getHostLanguage(); if (lang == net.sf.saxon.Configuration.XQUERY) { return "XQuery"; } else if (lang == net.sf.saxon.Configuration.XSLT) { return "XSLT"; } else if (lang == net.sf.saxon.Configuration.XPATH) { return "XPath"; } else { return "unknown"; } }If this method appears in class com.example.code.Utils
, then it can be
accessed using the following code in XSLT:
or the following in XQuery:
<line xmlns:nd="java:com.example.code.Utils"> { nd:HostLanguage() } </line>