Invoking and importing XQuery in XSLT

by Evan Lenz

In a couple of the recent articles introducing the XSLT API, I covered the required arguments and optional arguments of the xdmp:xslt-invoke() and xdmp:xslt-eval() functions. In other words, we looked at how to call XSLT from within XQuery. In this article, we'll look at the reverse: how you can call XQuery scripts and functions from within XSLT.

There are two primary ways to utilize XQuery from within XSLT. One is to invoke an XQuery script as a black box, using xdmp:invoke() or xdmp:eval(). For example, to insert the results of an XQuery script into your XSLT result, you might make a call like this:

In fact, that's how the various widgets on this website work. Even though RunDMC is an XSLT-based application, I didn't want to force all the MarkLogic developers to suddenly become XSLT developers. Also, I wanted them to be able to reuse XQuery scripts they had already written for things like displaying the latest top email threads from MarkMail. For situations like that, all they need to do is add an entry to the widgets.xml configuration file, pointing to the XQuery script they want to use to create the dynamic content. Behind the scenes, the XSLT calls xdmp:invoke() to insert the results of that XQuery script into the final XSLT results.

There is one other way to utilize XQuery from within XSLT, and we're using that in RunDMC also. Even though most of the RunDMC application is XSLT-based, the core data access functions are defined in XQuery. For certain things, such as querying and returning results in a particular order, XQuery can be a nicer choice than XSLT. Also, separating the core data access logic from the view layer enables XQuery developers who know nothing of XSLT to make enhancements, bug fixes, and optimizations to that core layer.

But this requires more than just invoking an XQuery script as a black box. We need to be able to call specific functions defined in XQuery from within XSLT. MarkLogic defines a top-level extension element (using XSLT's standard extension mechanism) for just that purpose. Here's how you import all the functions and global variable definitions from an XQuery module:

In RunDMC, we've compiled all such imports into one stylesheet module, aptly called xquery-imports.xsl. Note that, for the extension element to be correctly interpreted as such, you need to specify extension-element-prefixes="xdmp" on your <xsl:stylesheet> document element.

Given the above import, we can now call functions and reference variables defined in data-access.xqy. For example, here's an actual line from page.xsl that looks up all the comments for a given blog post:

I hope you've found this exploration useful. With just a few simple mechanisms, MarkLogic provides all the building blocks you need to combine XSLT and XQuery code in whatever way makes the most sense to you.