Project

Profile

Help

generate-id()

Added by Michael Staal-Olsen over 4 years ago

Hi!

Is it possible to mock the value of the generate-id function (mainly for testing purposes)? Or is it possible to make an integrated extension function (https://www.saxonica.com/html/documentation/extensibility/integratedfunctions/) in Java, which refers to the build in Saxon functions? For instance, can one make an extension function that invokes the generate-id() method?


Replies (5)

Please register to reply

RE: generate-id() - Added by Michael Kay over 4 years ago

An extension function can call fn:generate-id() using the static method net.sf.saxon.functions.GenerateId_1.generateId(nodeInfo). This returns a StringValue, whose getStringValue() method can be called to get the result as a Java String.

You could also perhaps try and modify Saxon's internal function library to cause a call on fn:generate-id() to bind to a different implementation. Try something like

net.sf.saxon.functions.registry.BuiltInFunctionSet.Entry entry = 
    configuration.getXslt30FunctionSet().getFunctionDetails("generate-id", 1);
entry.implementationClass = MyGenerateId.class;

where MyGenerateId is a subclass of net.sf.saxon.functions.GenerateId_1 that overrides the method public AtomicValue evaluate(Item arg, XPathContext context)

No guarantees on that one, however, and you'll probably need to be prepared to grovel around the source code to make it work.

Alternatively, you could provide your own implementation of generate-id() if you provide your own implementation of NodeInfo, but that's a rather substantial undertaking -- though not totally infeasible, if you make it extend AbstractNodeWrapper so it delegates most things to an underlying Saxon node implementation.

RE: generate-id() - Added by Michael Staal-Olsen over 4 years ago

Thanks for the reply, Michael! Do you know if the expression fn:generate-id() is equivalent with fn:generate-id(.) (with a dot indicating current node)? Currently, we use the single argument expression.

RE: generate-id() - Added by Michael Kay over 4 years ago

"Equivalent" here hides a lot of complexity. For a static call on generate-id#0 we convert it to a call on generate-id(.) at compile time. Dynamic calls on context-dependent functions are a bit more complex (because the context item is saved as part of the closure). It ends up being a call on generate-id(.) at run time, but the route by which it gets there is a bit devious.

RE: generate-id() - Added by Michael Staal-Olsen over 4 years ago

Thanks for the suggestion! Is there a "general" way of obtaining a NodeInfo instance from a Sequence / XdmValue / XdmNode? Right now I have some trouble understanding how to invoke the method in net.sf.saxon.functions.GenerateId_1 when my call method (in the extension function) has a signature of the form: Sequence call(XPathContext ctx, Sequence[] secs).

I guess it may be difficult to provide a general answer to the question, but if I for instance invoke the method in XSLT via the expression 'generate-id(.) ', then the dot would represent the current node. Ought it not to be possible to obtain a NodeInfo from this invocation?

RE: generate-id() - Added by Michael Kay over 4 years ago

If you've got a Sequence, call head() to find its first item, and cast it to NodeInfo. (That's assuming you know the sequence contains a single node; otherwise, do appropriate checks as you go).

If you've got an XdmValue, call itemAt(0) to find its first item, and cast the result to XdmNode. (Similar assumptions). Alternatively call XdmValue.getUnderlyingValue() to get the underlying Sequence, then proceed as above.

If you've got an XdmNode, call getUnderlyingValue() to get the corresponding NodeInfo.

    (1-5/5)

    Please register to reply