Project

Profile

Help

Feature #5558

open

Allow clients of SaxonJS to supply a map of custom XPath functions with arbitrary names

Added by Conal Tuohy 2 months ago. Updated about 2 months ago.

Status:
In Progress
Priority:
High
Assignee:
-
Category:
API
Sprint/Milestone:
Start date:
2022-06-10
Due date:
% Done:

0%

Estimated time:
Applies to JS Branch:
Fix Committed on JS Branch:
Fixed in JS Release:
SEF Generated with:
Platforms:
Company:
-
Contact person:
-
Additional contact persons:
-

Description

There's an existing mechanism whereby JavaScript functions which are in the global Window scope are automatically made available as XPath functions in a "js:" namespace, but this excludes use cases where it's desirable to add custom implementation functions in some standard namespace, e.g. the EXPath function libraries, XProc's XPath extension functions, etc.

I'd like to see this appear in the API in the same way that params member of the options object appears in the evaluate function; i.e. as an additional functions member of options, whose value is a JavaScript object mapping QNames to JavaScript functions.

Actions #1

Updated by Norm Tovey-Walsh about 2 months ago

  • Status changed from New to In Progress
  • Priority changed from Low to High
  • Sprint/Milestone set to SaxonJS 3.0

Coincidentally, I've just started working on this (or something very close to what you describe). The idea, as I'm conceiving it is:

  1. You write an xsl:function declaration that describes the function. Mark this with visibility='abstract' so that a function body isn't required (and maybe mark it also in some way to indicate that its implementation is expected to be provided at runtime).
  2. You register the JavaScript functions that implement your abstract functions in the SaxonJS runtime before calling transform or evaluating an XPath expression.
  3. The runtime manages argument and return types for the called JavaScript function.
Actions #2

Updated by Conal Tuohy about 2 months ago

I was hoping for the possibility of something usable in pure XPath (i.e. in SaxonJS.XPath.evaluate). I'm not sure if the approach you're looking at will be applicable in that case?

What I was hoping for (perhaps naively, since I haven't looked at the relevant source code) was to be able to more or less tap into whatever existing framework is currently responsible for raising JavaScript functions into XPath functions, but just to be able to supply the functions explicitly in the form of a JavaScript object mapping function QNames to JavaScript functions, rather than suppl them by exposing them in the global window scope, which inevitably puts some restrictions on the names of the resulting XPath functions, including that they all end up in a "js" namespace.

Actions #3

Updated by Conal Tuohy about 2 months ago

Accidentally/stupidly posted the above note instead of previewing it. I can't see a way to edit or delete it, so ... sorry for the evident misreading of your note: I do see that xsl:function doesn't imply the use of XSLT, and it's just about declaration.

I like it; it looks like it will do what I am hoping for. Pre-registering the functions with the runtime is obviously better than passing them to an evaluate call every time.

I wonder about the need for an explicit declaration (at the XPath level) of the parameters and return type, though? I can see how it would enable the runtime to perform type-coercion when marshaling parameters and results, e.g. to convert a number returned by a JS function into an xs:string or something if that's how the function's been declared. It seems to me, though, that an implementer at the JS level could just return JavaScript objects that have a well-defined mapping anyway; such as arrays, objects, functions, and otherwise you can use SaxonJS.atom to return particular types from their JS functions. Maybe the convenience of having the runtime do that for you is worth it, though, and maybe there's some other reason to have an explicit declaration, which I'm not seeing?

Actions #4

Updated by Norm Tovey-Walsh about 2 months ago

There is an edit button. It's the little thing on the right hand side across from the "Updated by" header that looks like a pencil in a checkbox. A microscopic pencil in an itty bitty checkbox.

Actions #5

Updated by John Lumley about 2 months ago

You will need a mechanism to supply a function type signature, if only to establish the arity and deeper to declare types of arguments and return. Without the latter, especially for arguments, you could get any form of argument supplied at runtime with no hope of any form of graceful type-mismatch recovery, unless your function deliberately does its own runtime type-checking, which will probably be expensive…

John Lumley

Sent from my iPad

On 16 Jun 2022, at 01:58, Saxonica Developer Community wrote:



Actions #6

Updated by Michael Kay about 2 months ago

We have in fact implemented a mechanism that allows you to supply both the function signature and a Javascript implementation, and we've used this to implement methods such as the EXPath binary library. The problem is that the data for the function signature is supplied in a rather low-level format, and for external use, we need to decide whether (a) to document this as is, or (b) to provide something with better usability.

Actions #7

Updated by Conal Tuohy about 2 months ago

Norm Tovey-Walsh wrote in #note-4:

There is an edit button. It's the little thing on the right hand side across from the "Updated by" header that looks like a pencil in a checkbox. A microscopic pencil in an itty bitty checkbox.

Thanks! But weirdly I'm still not seeing it; I have a quotation mark entitled "Quote", an ellipsis entitled "Actions" (which shows "Copy Link" if I click it), and a number providing a permalink.

John Lumley wrote in #note-5:

You will need a mechanism to supply a function type signature, if only to establish the arity and deeper to declare types of arguments and return. Without the latter, especially for arguments, you could get any form of argument supplied at runtime with no hope of any form of graceful type-mismatch recovery, unless your function deliberately does its own runtime type-checking, which will probably be expensive…

Yes it'd be nice to have type-checking (and type-coercion) built into the runtime, but BTW in JavaScript a function does have a length property analogous to XPath's function-arity function.

Please register to edit this issue

Also available in: Atom PDF Tracking page