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.Add (XdmModule)LibrarySet.Add (XdmModule)LibrarySet::Add (XdmModule^). 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 3.0 functions

Whilst XmlPrime does not yet implement XQuery 3.0/XPath 3.0, a number of the new functions have been implemented. Those functions in the XPath functions namespace 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 3.0. 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: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)

Math functions

Whilst XmlPrime does not yet implement XQuery 3.0/XPath 3.0, a number of the new functions have been implemented. Those functions in the Path math functions namespace are made available by the XdmModule.XPathMathFunctionsXdmModule.XPathMathFunctionsXdmModule::XPathMathFunctions property. These functions are specified in XPath and XQuery Functions and Operators 3.0.

  • 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?

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 implemented in .NET languages. There are two mechanisms for doing this. This document describes how to implement a module as a .NET class. Native modules can also be implemented inline in the stylesheet by using the <xp:script><xp:script><xp:script> element.

A module implemented by a .NET class contains a number of functions which are implemented as methods on the class. Which functions are exported, and the signatures of these functions can be controlled with the use of attributes.

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. Note that more than one module can implement a library with a particular namespace. A library can for example consist of an XQuery module and a native module.

If the target namespace of a module is not otherwise specified then it defaults to 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.
 

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.

  • If a function is implemented by a non-static method, then the class must have a public default constructor. In a future version of XmlPrime we hope to allow an instanciation of a class to be specified in the dynamic context settings.
  • Methods cannot take any external state. In a future version we hope 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 as well.

Native type mappings

The parameter and return types of methods exposed to XmlPrime are currently restricted to those that can be converted to XQuery types. Items can be represented by any of the CLR types listed in Mapping Atomic Types to CLR Types.

Sequences of items can be specified as arguments of the following types. The generic parameter must be set to one of the item types specified 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 XdmModuleAttributeXdmModuleAttributeXdmModuleAttribute, XdmFunctionAttributeXdmFunctionAttributeXdmFunctionAttribute and XdmTypeAttributeXdmTypeAttributeXdmTypeAttribute.

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 also allows the target namespace of the module to be specified.

XdmFunctionAttribute

Annotating a method with the XdmFunctionAttributeXdmFunctionAttributeXdmFunctionAttribute indicates that this method should be exported as part of the module. The LocalNameLocalNameLocalName property specifies the local name of the exported function. If the local name is not set, then the name of the method is used. If the class is annotated with the XdmModuleAttributeXdmModuleAttributeXdmModuleAttribute, and a containing is not annotated with the XdmFunctionAttributeXdmFunctionAttributeXdmFunctionAttribute then it will not be exported as part of the module.

XdmTypeAttribute

The XdmTypeAttributeXdmTypeAttributeXdmTypeAttribute can be used to specify the declared type of an argument or of the return type of the function. The attribute contains two properties, TypeCodeTypeCodeTypeCode and QuantifierQuantifierQuantifier; both of which must be set, and together which define the type. The TypeCodeTypeCodeTypeCode property is used to define the types of items in the sequence type, and the QuantifierQuantifierQuantifier property is used to define its cardinality.

Some .NET types can be used to represent more than one XQuery type. For example, xs:untypedAtomic is represented by stringStringString, so to write a function that returns xs:untypedAtomic values, you can write a function that returns a stringStringString and mark it with the following attribute:

 
[XdmType(XmlTypeCode.UntypedAtomic,Quantifier.One)]
 

Example

The following code demonstrates a module implementing a factorial function:

 
[XdmModule("http://www.example.org")]
class MyModule
{
    [XdmFunction("factorial")]
    public XPathAtomicValue MyFactorialFunction([XdmType(XmlTypeCode.Integer)] int argument)
    {
        if (argument <= 0)
            return 0;
        
        int factorial = 1;
        for (int i = 1; i <= argument; i++)
            factorial *= i;

        return 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.