XQuery/Creating XQuery Functions

Motivation edit

You want to avoid duplication of XQuery code or create more modular XQuery programs.

Method edit

Use XQuery functions to encapsulate any chunk of XQuery code with a function wrapper.

Any time you see a grouping of XQuery or XML code in your XQuery program that you would like to standardize, it is good design to start creating your own XQuery functions.

Static Content edit

Static content is content that is fixed and is not changed by the use of parameters. XQuery functions are ideal for storage of static content libraries.

For example, if all your HTML pages have the same block of code that has your logo and header text, you can create a simple XQuery function that encodes this functionality. Here is the HTML code you want to standardize on:

<div class="web-page-header">
   <img src="images/mylogo.jpg" alt="Our Logo"/>
   <h1>Acme Widgets Inc.</h1>
</div>
declare function local:header() as node() {
    <div class="web-page-header">
        <img src="images/mylogo.jpg" alt="Our Logo"/>
        <h1>Acme Widgets Inc.</h1>
    </div>
};

When you want to reference this you just call the function by placing it in your HTML page and enclosing it in curly braces:

<html>
   <head>
      <title>Sample Web Page</title>
   </head>
   <body>
     {local:header()}
   </body>
</html>

Note that these functions names are preceded by "local:". This is the default namespace of a function invoked only in the same XQuery main module.

If you want to store your functions in a separate file, you can do so. Such a file is called a "library module". To make use of the functions in this module, you need to "import" the module in the prolog of your query. The benefit of storing your code in functions and modules is that if you ever need to make a change to a function, you only have to make the change in one location, rather than in the many locations where you've copied and pasted the same code.

The following file, which we will save as webpage.xqm, is an example of this (note also the addition of a footer function):

module namespace webpage='http://www.example.com/webpage';

declare function webpage:header() as node() {
    <div class="web-page-header">
        <img src="images/mylogo.jpg" alt="Our Logo"/>
        <h1>Acme Widgets Inc.</h1>
    </div>
};

declare function webpage:footer() as node() {
    <div class="web-page-footer">
        <img src="images/mylogo.jpg" alt="Our Logo"/>
        <p>Acme Widgets Inc.</p>
    </div>
};

The module begins with a declaration of the module's namespace. Here we use an arbitrary namespace, "webpage".

Static Page Assembly edit

To use this function module you must import the module at the top of your XQuery file (the following "import module" expression assumes your XQuery file is in the same directory as the module file, webpage.xqm):

xquery version "1.0";

import module namespace webpage='http://www.example.com/webpage' at 'webpage.xqm';

let $title := 'Sample Web Page'
return
    <html>
        <head>
            <title>{$title}</title>
        </head>
        <body>
            {webpage:header()}
            <h1>{$title}</h1>
            <div class="content">Content goes here.</div>
            {webpage:footer()}
        </body>
    </html>

Dynamic Content edit

Unlike static content, dynamic content can be modified by including parameters into the function. One very common approach is to use a "page-assembler" function that includes parameters such as the document title and content. Here is an example of this function.

Dynamic Page Assembler Function edit

xquery version "1.0";

declare function webpage:assemble-page($title as xs:string, $content as node()) {
<html>
   <head>
      <title>{$title}</title>
   </head>
   <body>
     {webpage:header()}
     <h1>{$title}</h1>
     <div class="content">{$content}</div>
     {webpage:footer()}
   </body>
</html>
};

Your web pages now can all reference a central page assembler like the following.

import module namespace webpage='http://www.example.com/webpage' at 'webpage.xqm';

let $title := 'Sample Web Page'
let $content := <p>Content goes here.</p>

return webpage:assemble-page($title, $content)