Writing XQuery Module and Functions
XQuery modules are libraries of user-defined functions. An XQuery module contains one or multiple functions that you require to retrieve specific data from the CentraSite registry using the XML query language. You can create a module of functions in one XQuery file and then use the functions defined in that XQuery module in any other XQuery by using the import module directive. The user-defined functions belonging to the same context can be bundled into modules. Thus based upon these functions the implementation of complex queries within that context becomes much easier.
An XQuery module is made up of a prolog and a body. In CentraSite XQuery, the XQuery prolog is a series of definitions and functions that together create the required environment for query processing.
The XQuery prolog includes namespace declarations. The XQuery body is made up of a sequence of expressions that specify the intended query result.
Example:
module namespace au="http"//namespaces.CentraSite.com/modules/reports/apiusage";
import module namespace cs=
"http://namespaces.CentraSite.com/Schema/jarx";
import module namespace csdt=
"http://namespaces.CentraSite.com/modules/datetime";
import module namespace util=
"http://namespaces.CentraSite.com/jaxr/contants";
import module namespace util=
"http://namespaces.CentraSite.com/modules/util";
import module namespace cs1=
"http://namespaces.CentraSite.com/Schema";
The following XQuery is specified against the getAPIsWithAPIKeys declaration of integer type. The query retrieves the total number of APIs that use an API key to authenticate clients.
declare function au:getAPIsWithAPIKeys($noOfAssets as xs:integer)as node()*
{
(
let $ulp := csdt:getUserLocalePreferences()
for $assetKey in au:getUniqueAPIswithAPIKeys()
let $oi := collection("CentraSite")/cs:objectInfo[@v3key = @assetKey]
let $apiKeysCount := au:getNumberofAPIKeys($assetKey)
order by $apiKeysCount descending
return
<result>
<assetKey>{$assetKey}</assetKey>
<assetName>{if(empty($oi/cs:name)) then ()
else data(cs:localString($oi/cs:name, $ulp))}</assetName>
<assetDesc>{if(empty($oi/cs:description)) then ()
else data(cs:localString($oi/cs:description, $ulp))}</assetDesc>
<apiKeysCountForAsset>{$apiKeysCount}</apiKeysCountForAsset>
</results.
)[position() <= $noOfAssets]
}
Note the following from the previous query:
The XQuery prolog includes a namespace prefix (
cs) declaration, namespace
cs="http://namespaces.CentraSite.com/Schema/jarx";.
The
declare namespace keyword defines a namespace prefix (
cs) that is used later in the query body.
let $oi := collection("CentraSite")/cs:objectInfo[@v3key = @assetKey] is the query body.
CentraSite mandates XQuery modules and functions, especially for reports, when specifying data sets that are based on the CentraSite XQuery Data Source. The XQuery modules and functions help integrate the following functionality into the BIRT reports:
Identify data sources that connect your reports to the
CentraSite registry.
Identify data sets that specify the data to retrieve from the
CentraSite registry.
The XQuery functions must be written in the XQuery syntactical and semantical requirements of CentraSite, to specify the data to be retrieved from the registry and to be included in the data set, and return a list of registry objects as its result; therefore, you must have a good knowledge of XQuery language.
The following query retrieves all registry objects of type Organization from the CentraSite registry.
declare namespace cs="http://namespaces.CentraSite.com/Schema/jaxr";
for $ro in collection("CentraSite")/cs:organization return $ro
The syntax for user-defined functions, which are declared in the XQuery prolog, is as follows:
The syntax diagram tells us that a function declaration starts with the two words declare function followed by a QName. The QName (=qualified name) must be in a namespace, that is, either a default function namespace declaration must be in effect or the QName must use a prefix. When using a prefix, a namespace binding declaration can be avoided by using the prefix local.
The function's name is followed by a possibly empty comma-separated list of variables that is enclosed in parentheses. Each variable may optionally be accompanied by a type specification. Also the result type of a function may optionally be specified. The term enclosedexpr is an expression enclosed in curly braces that contains what the function returns if called or rather what the function call expression evaluates to (in functional language speak).
Thus the simplest query containing (and using) a function declaration in our sample is:
declare function au:getAPIsWithAPIKeys($noOfAssets as xs:integer)as node()*
This query returns the total number of APIs that use an API key to authenticate clients.
Once you have the user-defined XQuery function getAPIsWithAPIKeys() defined in the above XQuery format , you must enclose the function in an XQuery module. In our sample, we call this module as apiusage.
To enable queries to use user-defined functions without having to define them in every query, CentraSite XQuery allows for so called library modules. The declaration of such a library module is as follows:
A library module begins with the words module namespace followed by an NCName (a no-colon-name) that is used as a namespace prefix throughout the subsequent declarations. This is followed by an = sign and a string literal that specifies the namespace identifying the following declarations. This namespace specifier should be a URL that reflects the purpose of the module's content. The final semicolon (;) is optional due to compatibility reasons.
CentraSite stores modules in the database (Registry Repository) itself. After you create the required XQuery library module in to an XQuery file, you must upload it to the CentraSite Registry Repository.
A main module refers to library modules by importing the namespace that identifies the module's contents, that is, the module's target namespace as such:
A library module may be imported into a main module (or just as well into another library module) by writing import module namespace followed by a binding that binds a prefix to the library module's target namespace. The imported module's contents are then accessible using this prefix. The ability to bundle functions into modules can be exploited to make queries much more concise.
Thus the simplest way of importing a module in our sample is:
import module namespace cs="http://namespaces.CentraSite.com/Schema/jarx";
The final XQuery module would look like the following: