Project

Profile

Help

migrate XPathProcessor from SaxonHE 9.6 to 9.9

Added by Joern Turner over 4 years ago

Hi,

i'm migrating an XForms model processor to eXistd-db open source xml database. This processor uses a singleton XPathProcessor class to load a list of functions (about ~30) that are needed to support the XForms model and to create and run evaluations.

When trying to switch from SaxonHE 9.6 to something newer i ran into some compile errors cause some of the internals of Saxon have changed due to the architectural changes coming with XPath 3 / XQuery 3 (as i've already learned from Michael).

I have accepted the fact that an easy one-to-one migration of the code by just replacing certain classes with their new counterparts is not an option here as the changes are too big. So i'm ready to re-implement my XPathProcessor and functions as needed to work with latest SaxonHE version (and hopefully future ones).

As a first step i'd like to understand which route i should take through the API? From what i've learned from the docs i think that i should go for integrated extension functions and i found an example (the IsIdRef function) in the saxon sources of how such a function looks implemented. My functions should be in their own namespace but not require an prefix if possible. I even need to overwrite some builtin function like min(), max().

So, first question - are integrated extension functions a substainable way to handle these requirements?

For traditional reasons our former code relied on the older net.sf.saxon.sxpath package. Nowadays i read everywhere that S9 is the recommended one. However my data instances are in the form of a Xerces DOM where every node has several objects as userdata. I'm not sure how to wrap these instances with the Saxon builder or if that's even desirable (parsing twice?).

Which leads to the second question: which XPath API should i use and does this choice has an impact on the function implementations (other interfaces/mechanisms?).

Sorry for the long read - all comments, suggestions and guidances are highly appreciated.

Thanks a lot,

Joern


Replies (2)

RE: migrate XPathProcessor from SaxonHE 9.6 to 9.9 - Added by Michael Kay over 4 years ago

Firstly, the key to adding new functions and making them available to XPath expressions is the StaticContext interface, and in most cases Saxon will be using theIndependentContext implementation of that interface (different implementations are used, for example, for XPath expressions hosted within XSLT or XSD). The IndependentContext has a method getFunctionLibrary() and you need to add functions to this library. Generally the top-level function library will be a FunctionLibraryList which is a list of subsidiary function libaries, and to add functions, the clean approach is to add a new FunctionLibrary to that FunctionLibraryList.

So what kind of FunctionLibrary should you use? This depends on how you want to implement the functions (which presumably depends on what your existing implementations look like). Some possible candidates are:

  • BuiltInFunctionSet: for an example of one of these, see net.sf.saxon.ma.arrays.ArrayFunctionSet. The constructor of the BuiltInFunctionSet initialises the function library by calling register() for each function, supplying data about the function signature, and the actual implementation of the function goes in a class that extends SystemFunction: it generally only needs to implement a single method, call(), but it has the opportunity to implement other methods, for example to do compile-time optimisations if some of the function arguments are known statically.

  • IntegratedFunctionLibrary: this allows you to write each function as an instance of class ExtensionFunctionDefinition; in this case the metadata such as types of arguments is supplied by implementing methods such as getArgumentTypes().

  • A custom implementation: there's nothing to stop you writing your own implementation of FunctionLibrary if you want. See for example ConstructorFunctionLibrary which implements constructor functions such as xs:integer(xxx) for both built-in and user-defined atomic types.

If you're overriding built-in functions then you will need to make sure your function library is on the function library list before the built-in functions.

So long as you've constructed the function library correctly, it doesn't then matter which API is used to execute the XPath expression.

As regards use of Xerces DOM nodes, the standard Saxon net.sf.saxon.dom.DocumentWrapper can be used to wrap these nodes (as Saxon NodeInfo instances) to make them accessible to the XPath engine, and in your extension functions you can dive down from the wrapper NodeInfo class to the underlying DOM Node, and then cast it to a Xerces node to extract the custom properties. Do remember that the DOM is not thread-safe, even when reading.

RE: migrate XPathProcessor from SaxonHE 9.6 to 9.9 - Added by Joern Turner over 4 years ago

Thanks a lot Michael for the very fast response!

i already stumbled across BuiltInFunctionSet and i have a FunctionLibrary list too but having this clearly sorted now allows me to get started.

Joern

    (1-2/2)

    Please register to reply