Alex
Alex

Reputation: 29

How do I run XQuery in XSLT 3.0?

I'm trying to find a way to run XQuery within XSLT as I have a large library of XQuery logic that I've been using for enriching XML payloads in a Oracle database and I now need to migrate away from using this database but still carryout the enrichment logic in a new platform. The platform I'm migrating to supports XSLT 3.0 so I'm interested to first find a way to be able to run XQuery within XSLT. I've understood this to be possible by using fn:load-xquery-module() and I'm currently trying to mock this up in Oxygen XML Editor 24.0 (as this ships with Saxon EE 9.9.1.7 which is same as my Server runtime) however I don't get it working so far.

My XQuery module (saved in the same directory as my XSLT with file name myfuncs.xq):

module namespace myfuncs = "http://example.com/functions";

declare function myfuncs:double($num as xs:double) as xs:double {
  $num * 2
};

declare function myfuncs:triple($num as xs:double) as xs:double {
  $num * 3
};

My XSLT that attempts to use the XQuery module above (note, I've desensitised the URI paths below, in my local implementation they report the full absolute path):

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:myfuncs="http://example.com/functions"
    xmlns:fn="http://www.w3.org/2005/xpath-functions" 
    xmlns:saxon="http://saxon.sf.net/"
    exclude-result-prefixes="xs">
    
    <!-- Load the XQuery module -->
    <xsl:function name="myfuncs:double" as="xs:double">
        <xsl:param name="num" as="xs:double"/>
        <xsl:sequence select="fn:load-xquery-module('file:C:\Users\...\...\myfuncs.xq') ! myfuncs:double($num)"/>
    </xsl:function>
    
    <xsl:function name="myfuncs:triple" as="xs:double">
        <xsl:param name="num" as="xs:double"/>
        <xsl:sequence select="fn:load-xquery-module('file:C:\Users\...\...\myfuncs.xq') ! myfuncs:triple($num)"/>
    </xsl:function>
    
    <!-- Example usage -->
    <xsl:template match="/">
        <result>
            <double> <xsl:value-of select="myfuncs:double(5)"/> </double>
            <triple> <xsl:value-of select="myfuncs:triple(5)"/> </triple>
        </result>
    </xsl:template>
</xsl:stylesheet>

When I run this then I would expect my XQuery module to be loaded and myfuncs XQuery functions to be found and available for the XSLT, however instead I get the following error: Cannot locate module for namespace file:C:\Users...myfuncs.xq

Upvotes: 1

Views: 132

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167716

My working sample for load-xquery-module I have is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:functx="http://www.functx.com"
    exclude-result-prefixes="xs math functx"
    version="3.0">

    <xsl:variable name="functx-module" select="load-xquery-module('http://www.functx.com', map { 'location-hints' : 'http://www.xqueryfunctions.com/xq/functx-1.0-doc-2007-01.xq' })"/>

    <xsl:template name="xsl:initial-template" match="/">
        <xsl:sequence select="$functx-module?functions(xs:QName('functx:word-count'))?1('This is a test.')"/>
    </xsl:template>

</xsl:stylesheet>

Adapting that to your module (saved as module5.xqm in the same directory as the XSLT) gives

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xf="http://www.w3.org/2002/xforms"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:myfuncs="http://example.com/functions"
    exclude-result-prefixes="#all">

    <!-- Load the XQuery module -->

    <xsl:variable name="module5" select="load-xquery-module('http://example.com/functions', map { 'location-hints' : 'module5.xqm' })"/>
    
    <xsl:function name="myfuncs:double" as="xs:double">
        <xsl:param name="num" as="xs:double"/>
        <xsl:sequence select="$module5?functions(xs:QName('myfuncs:double'))?1($num)"/>
    </xsl:function>
    
    <xsl:function name="myfuncs:triple" as="xs:double">
        <xsl:param name="num" as="xs:double"/>
        <xsl:sequence select="$module5?functions(xs:QName('myfuncs:triple'))?1($num)"/>
    </xsl:function>
    
    <!-- Example usage -->
    <xsl:template match="/" name="xsl:initial-template">
        <result>
            <double> <xsl:value-of select="myfuncs:double(5)"/> </double>
            <triple> <xsl:value-of select="myfuncs:triple(5)"/> </triple>
        </result>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 2

Related Questions