Loading TOC...
Application Developer's Guide (PDF)

Application Developer's Guide — Chapter 5

Importing XQuery Modules, XSLT Stylesheets, and Resolving Paths

You can import XQuery into other XQuery and/or Server-Side JavaScript modules. Similarly, you can import XSLT stylesheets into other stylesheets, you can import XQuery modules into XSLT stylesheets, and you can import XSLT stylesheets into XQuery modules.

This chapter describes the two types of XQuery modules and specifies the rules for importing modules and resolving URI references. To import XQuery into Server-Side JavaScript modules, see Using XQuery Functions and Variables in JavaScript in the JavaScript Reference Guide.

This chapter covers the following topics:

For details on importing XQuery library modules into XSLT stylesheets and vice-versa, see Notes on Importing Stylesheets With <xsl:import> and Importing a Stylesheet Into an XQuery Module in the XQuery and XSLT Reference Guide.

XQuery Library Modules and Main Modules

There are two types of XQuery modules (as defined in the XQuery specification, http://www.w3.org/TR/xquer//#id-query-prolog):

For more details about the XQuery language, see the XQuery and XSLT Reference Guide.

Main Modules

A main module can be executed as an XQuery program, and must include a query body consisting of an XQuery expression (which in turn can contain other XQuery expressions, and so on). The following is a simple example of a main module:

"hello world"

Main modules can have prologs, but the prolog is optional. As part of a prolog, a main module can have function definitions. Function definitions in a main module, however, are only available to that module; they cannot be imported to another module.

Library Modules

A library module has a namespace and is used to define functions. Library modules cannot be evaluated directly; they are imported, either from other library modules or from main modules with an import statement. The following is a simple example of a library module:

xquery version "1.0-ml";
module namespace hello = "helloworld";

declare function helloworld()
{
  "hello world"
};

If you insert the module into the modules database of your App Server or save it on the filesystem under the modules root directory of your App Server, then you can import the module and call the helloworld function.

For example, suppose you save the above module to the filesystem with the pathname /my/app/helloworld.xqy. If you configure an App Server to use Modules as the modules database and / as the modules root, then you can store the module in the modules database as follows:

xquery version "1.0-ml";
xdmp:eval('xdmp:document-load("/space/rest/helloworld.xqy")', (),
  <options xmlns='xdmp:eval'>
    <database>{xdmp:database('Modules')}</database>
  </options>)

The inserted module has the URI /my/app/helloworld.xqy. Now, you can import the module in a main module or library module and call the helloworld function as follows:

xquery version "1.0-ml";
import module namespace hw="helloworld" at "/my/app/helloworld.xqy";

hw:helloworld()

The same import statement works if you configure an App server to use the filesystem as the modules database and / as the modules root. In this case, the query imports the module from the filesystem instead of from the modules database.

Rules for Resolving Import, Invoke, and Spawn Paths

In order to call a function that resides in an XQuery library module, you need to import the module with its namespace. MarkLogic Server resolves the library paths similar to the way other HTTP and application servers resolve their paths. Similarly, if you use xdmp:invoke or xdmp:spawn to run a module, you specify access to the module with a path. These rules also apply to the path to an XSLT stylesheet when using xdmp:xslt-invoke, as well as to stylesheet imports in the <xsl:import> or <xsl:include> instructions.

The XQuery module that is imported/invoked/spawned can reside in any of the following places:

  • In the Modules directory.
  • In a directory relative to the calling module.
  • Under the App Server root, which is either the specified directory in the Modules database (when the App Server is set to a Modules database) or the specified directory on the filesystem (when the App Server is set to find modules in the filesystem).

When resolving import/invoke/spawn paths, MarkLogic first resolves the root of the path, and then looks for the module under the Modules directory first and the App Server root second, using the first module it finds that matches the path.

The paths in import/invoke/spawn expressions are resolved as follows:

  1. When an import/invoke/spawn path starts with a leading slash, first look under the Modules directory (on Windows, typically c:\Program Files\MarkLogic\Modules). For example:
    import module "foo" at "/foo.xqy"; 

    In this case, it would look for the module file with a namespace foo in c:\Program Files\MarkLogic\Modules\foo.xqy.

  2. If the import/invoke/spawn path starts with a slash, and it is not found under the Modules directory, then start at the App Server root. For example, if the App Server root is /home/mydocs/, then the following import:
    import module "foo" at "/foo.xqy"; 

    will look for a module with namespace foo in /home/mydocs/foo.xqy.

    Note that you start at the App Server root, both for filesystem roots and Modules database roots. For example, in an App Server configured with a modules database and a root of http://foo/:

    import module "foo" at "/foo.xqy";

    will look for a module with namespace foo in the modules database with a URI http://foo/foo.xqy (resolved by appending the App Server root to foo.xqy).

  3. If the import/invoke/spawn path does not start with a slash, first look under the Modules directory. If the module is not found there, then look relative to the location of the module that called the function. For example, if a module at /home/mydocs/bar.xqy has the following import:
    import module "foo" at "foo.xqy"; 

    it will look for the module with namespace foo at /home/mydocs/foo.xqy.

    Note that you start at the calling module location, both for App Servers configured to use the filesystem and for App Servers configured to use modules databases. For example, a module with a URI of http://foo/bar.xqy that resides in the modules database and has the following import statement:

    import module "foo" at "foo.xqy"; 

    will look for the module with the URI http://foo/foo.xqy in the modules database.

  4. If the import/invoke/spawn path contains a scheme or network location, then the server throws an exception. For example:
    import module "foo" at "http://foo/foo.xqy"; 

    will throw an invalid path exception. Similarly:

    import module "foo" at "c:/foo/foo.xqy"; 

    will throw an invalid path exception.

Module Caching Notes

When XQuery modules (or XSLT files) are stored in the root for an App Server configured in MarkLogic Server, when they are first accessed, each module is parsed and then cached in memory so that subsequent access to the module is faster. If a module is updated, the cache is invalidated and each module for that App Server requires parsing again the next time it is evaluated. The module caching is automatic and therefore is transparent to developers. When considering the naming of modules, however, note the following:

  • The best practice is to use a file extension for a module corresponding to application/vnd.marklogic-xdmp or application/xslt+xml mimetypes. By default, this includes the extensions xqy, xq, and xslt. You can add other extensions to these mimetypes using the mimetypes configuration in the Admin Interface.
  • Any changes to modules that do not have a mimetype extension corresponding to application/vnd.marklogic-xdmp or application/xslt+xml will not invalidate the module cache, and therefore you must reload the cache on each host (for example, by restarting the server or modifying a module with the proper extension) to see changes in a module that does not have the correct extension.

Example Import Module Scenario

Consider the following scenario:

  • There is an HTTP server with a root defined as c:/mydir.
  • In a file called c:/mydir/lib.xqy, there is a library module with the function to import. The contents of the library module are as follows:
    xquery version "1.0-ml";
    module namespace hw="http://marklogic.com/me/my-module"; 
    
    declare function hello()
    {
    "hello"
    }; 
  • In a file called c:/mydir/main.xqy, there is an XQuery main module that imports a function from the above library module. This code is as follows:
    xquery version "1.0-ml";
    
    declare namespace my="http://marklogic.com/me/my-module";
    import module "http://marklogic.com/me/my-module" at "lib.xqy"; 
    
    my:hello() 

The library module lib.xqy is imported relative to the App Server root (in this case, relative to c:/mydir).

« Previous chapter
Next chapter »