Modules

A guide to using modules in XmlPrime, and writing Modules as .NET types.

This topic contains the following sections.

Overview

A module is a collection of functions and global variables, all in the same target namespace that can be called from within an XQuery program or XPath expression. A library is a set of modules all with the same target namespace. XmlPrime supports three types of modules: Built in modules, XQuery modules and native .NET modules. This document explains how modules are created and managed, and how to use them with XmlPrime.

The Library Set

All XQuery programs and XPath Expressions have an associated LibrarySetLibrarySetLibrarySet. The library set is exposed via the StaticContextSettings.LibrariesStaticContextSettings.LibrariesStaticContextSettings::Libraries property.

Modules can be added to the library set using the LibrarySet.AddLibrarySet.AddLibrarySet::Add. This makes the module accessible to the XQuery program or XPath expression. The module can only be used however if its target namespace has been imported. A library can be imported either by adding an import module declaration to an XQuery program, or by calling the StaticContextSettings.ImportModule (string)StaticContextSettings.ImportModule (String)StaticContextSettings::ImportModule (String^) method. This function has the same effect as a module import at the start of an XQuery program, and the import is not processed until the query is compiled. An overload of StaticContextSettings.ImportModule (XdmModule)StaticContextSettings.ImportModule (XdmModule)StaticContextSettings::ImportModule (XdmModule^) exists which adds the module to the library set and imports its target namespace.

When a module import is processed any modules with the specified target namespace that exist in the library set are imported. If there are no modules with the specified target namespace in the module set then the location hints are resolved using the module resolver specified in XQuerySettings.ModuleResolverXQuerySettings.ModuleResolverXQuerySettings::ModuleResolver and the modules are compiled and added to the library set. If there are modules with the specified target URI in the library set then the location hints are not processed.

After compiling an XQuery program or XPath expression all modules imported will have been added to the module set, and the library set can be reused.

 
 
Tip
The library set can be shared used for the compilation of more than one XQuery program or XPath expression. Using the same module set for multiple queries means that any libraries imported will only be compiled once.
 

Built in modules

XmlPrime contains a number of built in modules. These modules comprise functions that are available in various specifications but are not available by default in XPath 2.0.

These modules are added in the normal way (by adding the modules to the library set). Note that the libraries do not need to be imported in the query, as the http://www.w3.org/2005/xpath-functions namespace is imported by default.

Unlike other modules, if the same function exists in more than one imported built in module then there is no error. This is since if two built in functions have the same name and same signature then they are necessarily the same function.

XQuery 1.1 functions

Whilst XmlPrime does not yet implement XQuery 1.1/XPath 2.1, a number of the new functions have been implemented. These functions are made available by the XdmModule.XQuery11FunctionsXdmModule.XQuery11FunctionsXdmModule::XQuery11Functions property. These functions are a subset of the functions specified in XPath and XQuery Functions and Operators 1.1. In particular none of the functions in XQuery 1.0 and XPath 2.0 Functions and Operators (Second Edition) are included as these functions are already available in all languages supported by XmlPrime. The functions included in this library are:

  • fn:pi() as xs:double
  • fn:sqrt($arg as double?) as xs:double?
  • fn:sin($arg as double?) as xs:double?
  • fn:cos($arg as double?) as xs:double?
  • fn:tan($arg as double?) as xs:double?
  • fn:asin($arg as double?) as xs:double?
  • fn:acos($arg as double?) as xs:double?
  • fn:atan($arg as double?) as xs:double?
  • fn:format-number($value as numeric?, $picture as xs:string) as xs:string
  • fn:format-number($value as numeric?, $picture as xs:string, $decimal-format-name as xs:string) as xs:string
  • fn:format-dateTime($value as xs:dateTime?, $picture as xs:string) as xs:string?
  • fn:format-dateTime($value as xs:dateTime?, $picture as xs:string, $language as xs:string?, $calendar as xs:string?, $country as xs:string) as xs:string?
  • fn:format-date($value as xs:date?, $picture as xs:string) as xs:string?
  • fn:format-date($value as xs:date?, $picture as xs:string, $language as xs:string?, $calendar as xs:string?, $country as xs:string) as xs:string?
  • fn:format-time($value as xs:time?, $picture as xs:string) as xs:string?
  • fn:format-time($value as xs:time?, $picture as xs:string, $language as xs:string?, $calendar as xs:string?, $country as xs:string) as xs:string?
  • fn:format-integer($value as xs:integer?, $picture as xs:string) as xs:string
  • fn:format-integer($value as xs:integer?, $picture as xs:string, $language as xs:language) as xs:string
  • fn:round($arg as numeric?, $precision as xs:integer) as numeric? (this is in addition to the single argument version of fn:round defined in XQuery 1.0)
 
 
Warning
These functions were implemented based on an older draft version of the specification, and are liable to change in future versions of XmlPrime. In particular since the library was implemented the math functions hve been moved into a different namespace, and so may well be broken out into a seperate library.
 

XSLT functions

Whilst XmlPrime does not yet implement XSLT 2.0, a number of the new functions have been implemented. These functions are made available by the XdmModule.XsltFunctionsXdmModule.XsltFunctionsXdmModule::XsltFunctions property. These functions are a subset of the functions specified in XSL Transformations (XSLT) Version 2.0. Some of these functions currently always raise an error when used in XQuery or XPath. The functions included in this library are:

  • fn:document($uri-sequence as item()*) as node()*
  • fn:document($uri-sequence as item()*, $base-node as node()) as node()*
  • fn:format-number($value as numeric?, $picture as xs:string) as xs:string
  • fn:format-number($value as numeric?, $picture as xs:string, $decimal-format-name as xs:string) as xs:string
  • fn:format-dateTime($value as xs:dateTime?, $picture as xs:string) as xs:string?
  • fn:format-dateTime($value as xs:dateTime?, $picture as xs:string, $language as xs:string?, $calendar as xs:string?, $country as xs:string) as xs:string?
  • fn:format-date($value as xs:date?, $picture as xs:string) as xs:string?
  • fn:format-date($value as xs:date?, $picture as xs:string, $language as xs:string?, $calendar as xs:string?, $country as xs:string) as xs:string?
  • fn:format-time($value as xs:time?, $picture as xs:string) as xs:string?
  • fn:format-time($value as xs:time?, $picture as xs:string, $language as xs:string?, $calendar as xs:string?, $country as xs:string) as xs:string?
  • fn:unparsed-text($href as xs:string?) as xs:string?
  • fn:unparsed-text($href as xs:string?, $encoding as xs:string) as xs:string?
  • fn:unparsed-text-available($href as xs:string?) as xs:string?
  • fn:unparsed-text-available($href as xs:string?, $encoding as xs:string?) as xs:string?
  • fn:current() as item() (this is not supported in XQuery or XPath 2.0)
  • fn:current-group() as item()* (this is not supported in XQuery or XPath 2.0)
  • fn:current-grouping-key() as xs:anyAtomicType? (this is not supported in XQuery or XPath 2.0)
  • fn:generate-id() as xs:string
  • fn:generate-id($node as node()?) as xs:string
  • fn:system-property($property-name as xs:string) as xs:string
  • fn:function-available($function-name-name as xs:string, $arity as xs:integer) as xs:boolean
  • fn:function-available($function-name-name as xs:string) as xs:boolean
  • fn:key($key-name as xs:string, $key-value as xs:anyAtomicType*) as node()* (this is not supported in XQuery or XPath 2.0)
  • fn:key($key-name as xs:string, $key-value as xs:anyAtomicType*, $top as node()) as node()* (this is not supported in XQuery or XPath 2.0)

XmlPrime extension functions

XmlPrime 0.9 provided a suite of extension functions, as defined at XQuery 1.0 and XPath 2.0 Additional Functions 0.9. Whist many of these functions have been usurped by the XQuery 1.1 functions, the remaining functions are provided by a module exposed by XdmModule.ExtensionFunctionsXdmModule.ExtensionFunctionsXdmModule::ExtensionFunctions. The functions provided by this module are:

  • fn:e() as xs:double
  • fn:exp($arg as xs:double?) as xs:double?
  • fn:log($arg as xs:double?) as xs:double?
  • fn:log10($arg as xs:double?) as xs:double?
  • fn:pow($arg as xs:double?) as xs:double?
  • fn:atan2($arg1 as xs:double?, $arg2 as xs:double?) as xs:double?
  • fn:sinh($arg as xs:double?) as xs:double?
  • fn:cosh($arg as xs:double?) as xs:double?
  • fn:tanh($arg as xs:double?) as xs:double?
 
 
Warning
This library will likely change in a future version. In particular the target namespace may be changed, as new functions in the http://www.w3.org/2005/xpath-functions namespace are not fully spec-compliant.
 

XQuery modules

XQuery modules can be called from XQuery programs and XPath expressions. Currently the only way to add an XQuery module to the library set is by compiling an XQuery program that imports the module with an import module declaration. Note that if a module already exists in the library set then the import module declaration is ignored. The library set can then be reused for other queries and expressions.

In a future version of XmlPrime we intend it to be far easier to compile an external library for use in an XQuery program or XPath expression.

 
 
Note
In order for an XQuery library to behave correctly it must be compiled with the same schema set and name table as the main module.
 

Native modules

XmlPrime allows modules to be written as .NET types. A class is converted to an XdmModuleXdmModuleXdmModule instance by calling the XdmModule.NativeModule<T>XdmModule.NativeModule(Of T)XdmModule::NativeModule<T> method passing the class as a template parameter. This module can then be added to the library set for use in an XQuery program or XPath expression. A class used in this way is called a native module.

Restrictions for native functions

There are a number of restrictions on the functions that can be made available to an XQuery program or XPath expression. Many of these restrictions may be lifted in future versions.

  • Only static methods are exposed to the XQuery program or XPath expression. Similarly functions can take no external state. In a future version we hope to support instance methods as well, providing a class instance in the dynamic context settings, and to allow extra state information to be passed through to native functions called from an XQuery program or XPath expression.
  • Methods called from an XQuery program or XPath expression must be pure (have no side effects). Examples of side effects are writing a message to the console, or saving a result to a file. This is because there is no guarantee of what order user defined functions will be called in, how many times they will be called, or whether they will even be called, and these things will all be affected by query optimization. In a future version of XmlPrime we hope to support impure functions (via XQuery Scripting Extensions).
  • Methods called from an XQuery program or XPath expression must be deterministic. That is, when the function is called with the same arguments, it must return the same value. Examples of functions that are not deterministic are a function that returns a random number, or one that reads the contents of the specified file (as the contents may change during evaluation). This is required as optimizations such as common subexpression elimination assume this property. In a future version of XmlPrime we hope to support non-deterministic functions (this is part of XQuery 1.1).

Native type mappings

The parameter and return types of methods exposed to XmlPrime are restricted to those that can be converted to XQuery types. In the current version, items passed as arguments or return values are limited to the following.

CLR TypeXDM Type 
XPathItemXPathItemXPathItem item() The type of values passed or returned must be either XPathNavigatorXPathNavigatorXPathNavigator (for subtypes of node()) or XPathAtomicValueXPathAtomicValueXPathAtomicValue (for subtypes of xs:anyAtomicType) instances.
XPathNavigatorXPathNavigatorXPathNavigator node()  
XPathAtomicValueXPathAtomicValueXPathAtomicValue xs:anyAtomicType  
 
 
Note
In a future version we intend to support the full range of types specified in
Mapping Atomic Types to CLR Types
 

Sequences of types can be specified as arguments of the following types. The generic parameter must be set to one of the item types listed above.

T[] Evaluated eagerly (entire sequence is evaluated together).
List<T>List(Of T)List<T> Evaluated eagerly (entire sequence is evaluated together).
IEnumerable<T>IEnumerable(Of T)IEnumerable<T> Evaluated lazily (items are evaluated as they are retrieved).
IEnumerator<T>IEnumerator(Of T)IEnumerator<T> Evaluated lazily (items are evaluated as they are retrieved).

Module annotations

Native libraries can be annotated via the use of the XdmModuleAttributeXdmModuleAttributeXdmModuleAttribute.

If a class is not annotated then the target namespace of the module is the URI with scheme clitype and path equal to the CLI full name of the .NET type. For example the class System.MathSystem.MathSystem::Math would be exported as a module with target namespace clitype:System.Math.

 
 
Note
In a future version of XmlPrime we intend to use this URI syntax as a way of specifying types as location hints.
 

If a class is not annotated then all methods that satisfy the conditions to be used in an XQuery program or XPath expression will be exported with their local name equivalent to their name in .NET.

Annotating a class with the XdmModuleAttributeXdmModuleAttributeXdmModuleAttribute attribute adds greater control over the functions that are exported, and the names used to export them. The XdmModuleAttributeXdmModuleAttributeXdmModuleAttribute allows the target namespace of the module to be specified.

The XdmFunctionAttributeXdmFunctionAttributeXdmFunctionAttribute attribute can be applied to methods in an annotated library, and can be used to specify the local name that should be used to export the function. Only methods marked with this attribute will be exported. If the containing class is not annotated with XdmModuleAttributeXdmModuleAttributeXdmModuleAttribute, then the XdmFunctionAttributeXdmFunctionAttributeXdmFunctionAttribute attribute is ignored.

 
 
Note
In the future we intend to support additional annotations to specify more accurately the static types of the exported function, and in particular we intend to be able to specify any sequence type for the parameter or return types of an exported function.
 

Example

The following code demonstrates a module implementing a factorial function:

 
[XdmModule("http://www.example.org")]
class MyModule
{
    [XdmFunction("factorial")]
    public XPathAtomicValue MyFactorialFunction(XPathAtomicValue argument)
    {
        if (!XmlSchemaType.IsDerivedFrom(argument.XmlType, 
                                          XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Integer),
                                          XmlSchemaDerivationMethod.None))
            throw new ArgumentException("Argument must be an integer", "argument");
                          
        decimal decimalArgument = argument.ValueAsDecimal;
                      
        decimal factorial = 1;
        for (decimal i = 1; i <= decimalArgument; i++)
            factorial *= i;
                          
        return XPathAtomicValue.CreateInteger(factorial);
    }
}
 

Note that this class is annotated to export the function factorial in the namespace http://www.example.org. The following code shows how to compile a query that uses this external module to calculate 10 factorial, and write out the result to the console.

 
XmlNameTable nameTable = new NameTable();
XQuerySettings querySettings = new XQuerySettings(nameTable)
XdmModule module = XdmModule.NativeModule<MyModule>();
querySettings.Libraries.Add(module)

string program = "import module namespace module='http://www.example.org';" + Environment.NewLine +;
                 "module:factorial(10)";

XQuery query = XQuery.Compile(program, querySettings);

XPathItem result = query.EvaluateToItem();

Console.WriteLine(result.ToString());
 

For more information on creating a native module, see the documentation for the XdmModule.NativeModule<T>XdmModule.NativeModule(Of T)XdmModule::NativeModule<T> method.