Made UI more complete. possible to stop/start/close receivers and there is a reporting page.

xquery version "3.0";

module namespace app="http://exist-db.org/extension/jms/templates";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://exist-db.org/extension/jms/config" at "config.xqm";
import module namespace jms="http://exist-db.org/xquery/messaging" at "java:org.exist.messaging.xquery.MessagingModule";

(:~
 : This is a sample templating function. It will be called by the templating module if
 : it encounters an HTML element with an attribute: data-template="app:test" or class="app:test" (deprecated).
 : The function has to take 2 default parameters. Additional parameters are automatically mapped to
 : any matching request or function parameter.
 :
 : @param $node the HTML node with the attribute which triggered this call
 : @param $model a map containing arbitrary data - used to pass information between template calls
 :)
declare function app:test($node as node(), $model as map(*)) {

Dummy template output generated by function app:test at {current-dateTime()}. The templating
        function was triggered by the class attribute class="app:test".

};

declare function app:executeAction($node as node(), $model as map(*), $action as xs:string, $receiver as xs:int) {

{

        try {
            switch ($action)
               case "start" return jms:start($receiver)
               case "stop"  return jms:stop($receiver)
               case "close" return jms:close($receiver)
               default return "unknown action"
        } catch * {

            {$err:description}

        }

        }

};

declare function app:showReport($node as node(), $model as map(*), $show as xs:string, $receiver as xs:int) {

{
        try {
        let $report := jms:report($receiver)
        return

JMS configuration

                    Item	Value

id	{data($report/@id)}

state	{data($report/state)}

java.naming.factory.initial	{data($report/java.naming.factory.initial)}

java.naming.provider.url	{data($report/java.naming.provider.url)}

connection-factory	{data($report/connection-factory)}

connection.username	{data($report/connection.username)}

destination	{data($report/destination)}

connection.client-id	{data($report/connection.client-id)}

consumer.message-selector	{data($report/consumer.message-selector)}

usage	{data($report/usage)}

Statistics

                        Item	Value

nrProcessedMessages	{data($report/statistics/nrProcessedMessages)}

nrUnprocessedMessages	{data($report/statistics/nrUnprocessedMessages)}

cumulativeProcessingTime	{data($report/statistics/cumulativeProcessingTime)}

Errors

                        Source	Message

                    {
                        for $error in $report/errorMessages/error
                        return

{data($error/@src)}	{data($error)}

                    }

        } catch * {

            {$err:description}

        }
        }

};

declare function app:showReceivers($node as node(), $model as map(*)) {

    try {

                Id	State	Action	URL	Destination	Client-id	P	F	E

        {
            for $id in jms:list()
            let $report := jms:report($id)
            let $nrErrors := count($report/errorMessages/error)
            return

                {data($report/@id)}
                {data($report/state)}

                {data($report/java.naming.provider.url)}
                {data($report/destination)}
                {data($report/connection.client-id)}
                {data($report/statistics/nrProcessedMessages)}
                {data($report/statistics/nrUnprocessedMessages)}

                {

                    if($nrErrors eq 0)
                    then
                       $nrErrors
                    else
                        {$nrErrors}
                }

        }

    } catch * {

            {$err:description}

    }

};

xquery version "3.0";

module namespace app="http://exist-db.org/extension/jms/templates";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://exist-db.org/extension/jms/config" at "config.xqm";
import module namespace jms="http://exist-db.org/xquery/messaging" at "java:org.exist.messaging.xquery.MessagingModule";

(:~
 : This is a sample templating function. It will be called by the templating module if
 : it encounters an HTML element with an attribute: data-template="app:test" or class="app:test" (deprecated).
 : The function has to take 2 default parameters. Additional parameters are automatically mapped to
 : any matching request or function parameter.
 :
 : @param $node the HTML node with the attribute which triggered this call
 : @param $model a map containing arbitrary data - used to pass information between template calls
 :)
declare function app:test($node as node(), $model as map(*)) {

Dummy template output generated by function app:test at {current-dateTime()}. The templating
        function was triggered by the class attribute class="app:test".

};

declare function app:executeAction($node as node(), $model as map(*), $action as xs:string, $receiver as xs:int) {

{

        try {
        switch ($action)
           case "start" return jms:start($receiver)
           case "stop"  return jms:stop($receiver)
           case "close" return jms:close($receiver)
           default return "unknown action"
        } catch * {

            {$err:description}

        }

        }

};

declare function app:showReport($node as node(), $model as map(*), $show as xs:string, $receiver as xs:int) {

{

        let $report := jms:report($receiver)
        return

JMS configuration

                    Item	Value

id	{data($report/@id)}

state	{data($report/state)}

java.naming.factory.initial	{data($report/java.naming.factory.initial)}

java.naming.provider.url	{data($report/java.naming.provider.url)}

connection-factory	{data($report/connection-factory)}

connection.username	{data($report/connection.username)}

destination	{data($report/destination)}

connection.client-id	{data($report/connection.client-id)}

consumer.message-selector	{data($report/consumer.message-selector)}

usage	{data($report/usage)}

Statistics

                        Item	Value

nrProcessedMessages	{data($report/statistics/nrProcessedMessages)}

nrUnprocessedMessages	{data($report/statistics/nrUnprocessedMessages)}

cumulativeProcessingTime	{data($report/statistics/cumulativeProcessingTime)}

Errors

                        Source	Message

                    {
                        for $error in $report/errorMessages/error
                        return

{data($error/@src)}	{data($error)}

                    }

        }

};

declare function app:showReceivers($node as node(), $model as map(*)) {

    try {

                Id	State	Action	URL	Destination	Client-id	P	F	E

        {
            for $id in jms:list()
            let $report := jms:report($id)
            let $nrErrors := count($report/errorMessages/error)
            return

                {data($report/@id)}
                {data($report/state)}

                {data($report/java.naming.provider.url)}
                {data($report/destination)}
                {data($report/connection.client-id)}
                {data($report/statistics/nrProcessedMessages)}
                {data($report/statistics/nrUnprocessedMessages)}

                {

                    if($nrErrors eq 0)
                    then
                       $nrErrors
                    else
                        {$nrErrors}
                }

        }

    } catch * {

            {$err:description}

    }

};


[ignore] small fix to twitter xquery script.

svn path=/stable/eXist-1.4.x/; revision=11297

xquery version "1.0";

(: This is the view part of the twitter client app. twitter.xql forwards
   the twitter timeline in the request attribute "twitter.feed". :)

declare namespace tc="http://exist-db.org/xquery/twitter-client";
declare namespace atom="http://www.w3.org/2005/Atom";
declare namespace html="http://www.w3.org/1999/xhtml";

(: Parse the twitter message string. This function will recognize user names, links
   and tags. :)
declare function tc:parse-content($content as xs:string) {
    let $filtered_text := $content
    let $filtered_text := replace($filtered_text,"(http://[A-z0-9/\.?=&\-_%]+)",'$1')
    let $filtered_text := replace($filtered_text,"@([A-z0-9/\.\-_]+)", '@$1')
	let $filtered_text := replace($filtered_text, "^([A-z0-9/\.\-_]+):", '$1:')
    let $filtered_text := replace($filtered_text,"&#([x0-9]+);","entity:$1")
    let $filtered_text := replace($filtered_text,"(&)","$1amp;")
    let $filtered_text := replace($filtered_text,"#([A-z0-9/\-_]+)", '#$1')
    let $filtered_text := replace($filtered_text,"\[\[entity:([x0-9]+)\]\]","&#$1;")
    let $filtered_text := concat("", $filtered_text, "")
    return util:parse($filtered_text)
};

(: Format an atom entry :)
declare function tc:print-entry($entry as element(atom:entry), $mode as xs:string) {
    let $currentDate := adjust-date-to-timezone(current-date(), xs:dayTimeDuration("PT0H"))
    let $date := xs:dateTime($entry/atom:published)
    let $dateLine :=
        if (xs:date($date) eq $currentDate) then
            xs:time($date)
        else
            $date
    return

		{
			if ($mode eq 'html') then

			else ()
		}

                {$dateLine}
                {tc:parse-content($entry/atom:content/node())}

};

(: scan a set of HTML option elements and select the one whose value matches
   the $select argument :)
declare function tc:set-options($select as xs:string, $options as element(html:option)+) {
    for $opt in $options
    return
        element { node-name($opt) } {
            if ($opt/@value eq $select) then
                attribute selected { "true" }
            else
                (),
            $opt/@*, $opt/node()
        }
};

(: twitter.xql passes the timeline feed in request attribute "twitter.feed" :)
let $feed := request:get-attribute("twitter.feed")
let $user := request:get-parameter("user", ())
let $view := request:get-parameter("view", "user")
let $mode := request:get-parameter("mode", "html")
let $max := number(request:get-parameter("max", -1))
let $formattedFeed :=
	if ($feed) then
		if ($feed instance of xs:string) then

Twitter reported an error: {$feed}

		else
			let $entries :=
				for $entry in $feed/atom:entry
				order by xs:dateTime($entry/atom:published) descending
				return $entry
			let $subset :=
				if ($max lt 0) then
					$entries
				else
					subsequence($entries, 1, $max)
			for $entry in $subset
			return
				tc:print-entry($entry, $mode)
	else ()
return
	if ($mode eq 'html') then

					<form method="GET">
						User:
						<input type="text" name="user" size="15"
							value="{if ($user) then $user else 'existdb'}"/>
						<select name="view">
						{
							tc:set-options($view, (
								<option value="user">User Timeline</option>,
								<option value="friends">Friends Timeline</option>
							))
						}
						</select>
						<input type="submit" value="Show"/>
					</form>

To view the friends timeline, edit twitter.xql and set variable
						$tc:login to a valid twitter user/password.

					{ $formattedFeed }

View source: twitter.xql,
			     twitter-view.xql

	else
		let $null := util:declare-option("exist:serialize", "method=text media-type=application/json")
		let $asString :=
			translate(
				replace(
					util:serialize($formattedFeed, "indent=no"),
					"'", "\\'"
				),
				'
', ''
			)
		let $body := concat('<ul class="twitter">', $asString, '</ul>')
		return
			concat("twitterCallback('", $body, "')")

xquery version "1.0";

(: This is the view part of the twitter client app. twitter.xql forwards
   the twitter timeline in the request attribute "twitter.feed". :)

declare namespace tc="http://exist-db.org/xquery/twitter-client";
declare namespace atom="http://www.w3.org/2005/Atom";
declare namespace html="http://www.w3.org/1999/xhtml";

(: Parse the twitter message string. This function will recognize user names, links
   and tags. :)
declare function tc:parse-content($content as xs:string) {
    let $filtered_text := $content
    let $filtered_text := replace($filtered_text,"(http://[A-z0-9/\.?=&\-_%]+)",'$1')
    let $filtered_text := replace($filtered_text,"@([A-z0-9/\.\-_]+)", '@$1')
	let $filtered_text := replace($filtered_text, "^([A-z0-9/\.\-_]+):", '$1:')
    let $filtered_text := replace($filtered_text,"&#([x0-9]+);","entity:$1")
    let $filtered_text := replace($filtered_text,"(&)","$1amp;")
    let $filtered_text := replace($filtered_text,"#([A-z0-9/\-_]+)", '#$1')
    let $filtered_text := replace($filtered_text,"\[\[entity:([x0-9]+)\]\]","&#$1;")
    let $filtered_text := concat("", $filtered_text, "")
    return util:parse($filtered_text)
};

(: Format an atom entry :)
declare function tc:print-entry($entry as element(atom:entry), $mode as xs:string) {
    let $currentDate := adjust-date-to-timezone(current-date(), xs:dayTimeDuration("PT0H"))
    let $date := xs:dateTime($entry/atom:published)
    let $dateLine :=
        if (xs:date($date) eq $currentDate) then
            xs:time($date)
        else
            $date
    return

		{
			if ($mode eq 'html') then

			else ()
		}

                {$dateLine}
                {tc:parse-content($entry/atom:content/node())}

};

(: scan a set of HTML option elements and select the one whose value matches
   the $select argument :)
declare function tc:set-options($select as xs:string, $options as element(html:option)+) {
    for $opt in $options
    return
        element { node-name($opt) } {
            if ($opt/@value eq $select) then
                attribute selected { "true" }
            else
                (),
            $opt/@*, $opt/node()
        }
};

(: twitter.xql passes the timeline feed in request attribute "twitter.feed" :)
let $feed := request:get-attribute("twitter.feed")
let $user := request:get-parameter("user", ())
let $view := request:get-parameter("view", "user")
let $mode := request:get-parameter("mode", "html")
let $max := number(request:get-parameter("max", -1))
let $formattedFeed :=
	if ($feed) then
		if ($feed instance of xs:string) then

Twitter reported an error: {$feed}

		else
			let $entries :=
				for $entry in $feed/atom:entry
				order by xs:dateTime($entry/atom:published) descending
				return $entry
			let $subset :=
				if ($max lt 0) then
					$entries
				else
					subsequence($entries, 1, $max)
			for $entry in $subset
			return
				tc:print-entry($entry, $mode)
	else ()
return
	if ($mode eq 'html') then

					<form method="GET">
						User:
						<input type="text" name="user" size="15"
							value="{if ($user) then $user else 'existdb'}"/>
						<select name="view">
						{
							tc:set-options($view, (
								<option value="user">User Timeline</option>,
								<option value="friends">Friends Timeline</option>
							))
						}
						</select>
						<input type="submit" value="Show"/>
					</form>

To view the friends timeline, edit twitter.xql and set variable
						$tc:login to a valid twitter user/password.

					{ $formattedFeed }

View source: twitter.xql,
			     twitter-view.xql

	else
		let $null := util:declare-option("exist:serialize", "method=text media-type=application/json")
		let $asString := replace(util:serialize($formattedFeed, "indent=no"), "'", "\\'")
		let $body := concat('<ul class="twitter">', $asString, '</ul>')
		return
			concat("twitterCallback('", $body, "')")


[documentation] Incorrect index configuration for documentation search.

svn path=/stable/eXist-1.4.x/; revision=15003

module namespace docs="http://exist-db.org/xquery/admin/fundocs";

import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace xqdm="http://exist-db.org/xquery/xqdoc";

declare namespace xqdoc="http://www.xqdoc.org/1.0";

declare variable $docs:COLLECTION := "/db/xqdocs";

(:~
    Collection configuration for the function docs. We use an ngram
    index for fast substring searches.
:)
declare variable $docs:config :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xqdoc="http://www.xqdoc.org/1.0">
            <fulltext default="none" attributes="no"/>
            <lucene>
                <analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer"/>
                <text qname="section">
                    <ignore qname="title"/>
                    <ignore qname="programlisting"/>
                    <ignore qname="screen"/>
                    <ignore qname="synopsis"/>
                </text>
                <text qname="title" boost="2.0"/>
            </lucene>
            <ngram qname="xqdoc:name"/>
            <ngram qname="xqdoc:description"/>
        </index>
    </collection>;

declare function docs:main() as element() {
    let $action := request:get-parameter("action", ())
    let $context := request:get-context-path()
    return

Install Documentation

This form is used to extract function module documentation and to make
            the main documentation searchable.

            {
                if ($action) then

Processed:

                        {
                            if ($action eq 'generate') then
                                docs:setup()
                            else if ($action eq 'load') then
                                docs:action-load()
                            else
                                ()
                        }

Continue to search documentation or
                            function libraries.

                else
                    ()
            }

            <form action="{session:encode-url(request:get-uri())}" method="GET">
                <input type="hidden" name="panel" value="fundocs"/>

Automatically Generate and Index the Documentation

                    <button type="submit" name="action"
                        value="generate">Generate</button>

Extract Documentation for Selected XQuery Modules

                        Choose known module:
                        <select name="uri2">
                            <option></option>
                        {
                            for $uri in util:mapped-modules()
                            return
                                <option>{$uri}</option>
                        }
                        </select>

                        or enter module URI:
                        <input type="text" name="uri" size="40"/>

                        <button type="submit" name="action"
                            value="load">Load</button>

            </form>

};

declare function docs:action-load() {
    let $uri1 := request:get-parameter("uri", "")
    let $uri2 := request:get-parameter("uri2", "")
    let $uri := if (string-length($uri1) gt 0) then $uri1 else $uri2
    let $setup :=
        if (empty(collection("/db/xqdocs"))) then
            docs:configure()
        else
            ()
    return
        if (string-length($uri) gt 0) then
            docs:load-external($uri)
        else ()
};

declare function docs:create-collection($parent as xs:string, $child as xs:string) as empty() {
    let $null := xdb:create-collection($parent, $child)
    return ()
};

declare function docs:configure() {
    let $null := (
       	docs:create-collection("/db/system/config", "db"),
       	docs:create-collection("/db/system/config/db", "xqdocs"),
       	xdb:store("/db/system/config/db/xqdocs", "collection.xconf", $docs:config),
       	docs:create-collection("/db", "xqdocs"),
       	xdb:chmod-collection("/db/xqdocs", 508)
    ) return ()
};

declare function docs:load-external($uri as xs:string) {
    let $xml := xqdm:scan(xs:anyURI($uri))
    let $moduleURI := $xml//xqdoc:module/xqdoc:uri
    let $docName := concat(util:hash($moduleURI, "MD5"), ".xml")
    let $null := (
		xdb:store($docs:COLLECTION, $docName, $xml),
		xdb:chmod-resource($docs:COLLECTION, $docName, 508)
	)
	return

Extracted docs from external module {$moduleURI}

};

declare function docs:load-external-modules() {
    for $uri in util:mapped-modules()
    return
        docs:load-external($uri)
};

declare function docs:load-internal-modules() {
    for $moduleURI in util:registered-modules()
	let $moduleDocs := util:extract-docs($moduleURI)
	let $docName := concat(util:hash($moduleURI, "MD5"), ".xml")
	return
	   if ($moduleDocs) then
            let $null := (
    		  xdb:store($docs:COLLECTION, $docName, $moduleDocs),
    		  xdb:chmod-resource($docs:COLLECTION, $docName, 508)
            )
            return

Extracted docs from builtin module {$moduleURI}

	   else

No content for module {$moduleURI}

};

declare function docs:load-fundocs() {
	docs:load-internal-modules(),
	docs:load-external-modules()
};

declare function docs:load-documentation() {
	let $home := system:get-exist-home()
	let $dir :=
		if (doc-available(concat("file:///", $home, "/webapp/download.xml"))) then
			concat($home, "/webapp")
		else if(ends-with($home, "WEB-INF")) then
			substring-before($home, "WEB-INF")
		else
			concat($home)
	let $stored :=
		xdb:store-files-from-pattern($docs:COLLECTION, $dir, "*.xml", "text/xml")
	for $path in $stored
	return

{$path}

};

declare function docs:setup() as element(ul) {

    {
       	docs:configure(),
       	docs:load-fundocs(),
       	docs:load-documentation()
    }

};

module namespace docs="http://exist-db.org/xquery/admin/fundocs";

import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace xqdm="http://exist-db.org/xquery/xqdoc";

declare namespace xqdoc="http://www.xqdoc.org/1.0";

declare variable $docs:COLLECTION := "/db/xqdocs";

(:~
    Collection configuration for the function docs. We use an ngram
    index for fast substring searches.
:)
declare variable $docs:config :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xqdoc="http://www.xqdoc.org/1.0">
            <fulltext default="none" attributes="no"/>
            <lucene>
                <analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer"/>
                <text qname="section">
                    <ignore qname="title"/>
                    <ignore qname="programlisting"/>
                    <ignore qname="screen"/>
                    <ignore qname="synopsis"/>
                </text>
                <text qname="title" boost="2.0"/>
            </lucene>
            <lucene>
                <analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer"/>
                <text qname="para"/>
                <text qname="title" boost="2.0"/>
                <ignore qname="title"/>
            </lucene>
            <ngram qname="xqdoc:name"/>
            <ngram qname="xqdoc:description"/>
        </index>
    </collection>;

declare function docs:main() as element() {
    let $action := request:get-parameter("action", ())
    let $context := request:get-context-path()
    return

Install Documentation

This form is used to extract function module documentation and to make
            the main documentation searchable.

            {
                if ($action) then

Processed:

                        {
                            if ($action eq 'generate') then
                                docs:setup()
                            else if ($action eq 'load') then
                                docs:action-load()
                            else
                                ()
                        }

Continue to search documentation or
                            function libraries.

                else
                    ()
            }

            <form action="{session:encode-url(request:get-uri())}" method="GET">
                <input type="hidden" name="panel" value="fundocs"/>

Automatically Generate and Index the Documentation

                    <button type="submit" name="action"
                        value="generate">Generate</button>

Extract Documentation for Selected XQuery Modules

                        Choose known module:
                        <select name="uri2">
                            <option></option>
                        {
                            for $uri in util:mapped-modules()
                            return
                                <option>{$uri}</option>
                        }
                        </select>

                        or enter module URI:
                        <input type="text" name="uri" size="40"/>

                        <button type="submit" name="action"
                            value="load">Load</button>

            </form>

};

declare function docs:action-load() {
    let $uri1 := request:get-parameter("uri", "")
    let $uri2 := request:get-parameter("uri2", "")
    let $uri := if (string-length($uri1) gt 0) then $uri1 else $uri2
    let $setup :=
        if (empty(collection("/db/xqdocs"))) then
            docs:configure()
        else
            ()
    return
        if (string-length($uri) gt 0) then
            docs:load-external($uri)
        else ()
};

declare function docs:create-collection($parent as xs:string, $child as xs:string) as empty() {
    let $null := xdb:create-collection($parent, $child)
    return ()
};

declare function docs:configure() {
    let $null := (
       	docs:create-collection("/db/system/config", "db"),
       	docs:create-collection("/db/system/config/db", "xqdocs"),
       	xdb:store("/db/system/config/db/xqdocs", "collection.xconf", $docs:config),
       	docs:create-collection("/db", "xqdocs"),
       	xdb:chmod-collection("/db/xqdocs", 508)
    ) return ()
};

declare function docs:load-external($uri as xs:string) {
    let $xml := xqdm:scan(xs:anyURI($uri))
    let $moduleURI := $xml//xqdoc:module/xqdoc:uri
    let $docName := concat(util:hash($moduleURI, "MD5"), ".xml")
    let $null := (
		xdb:store($docs:COLLECTION, $docName, $xml),
		xdb:chmod-resource($docs:COLLECTION, $docName, 508)
	)
	return

Extracted docs from external module {$moduleURI}

};

declare function docs:load-external-modules() {
    for $uri in util:mapped-modules()
    return
        docs:load-external($uri)
};

declare function docs:load-internal-modules() {
    for $moduleURI in util:registered-modules()
	let $moduleDocs := util:extract-docs($moduleURI)
	let $docName := concat(util:hash($moduleURI, "MD5"), ".xml")
	return
	   if ($moduleDocs) then
            let $null := (
    		  xdb:store($docs:COLLECTION, $docName, $moduleDocs),
    		  xdb:chmod-resource($docs:COLLECTION, $docName, 508)
            )
            return

Extracted docs from builtin module {$moduleURI}

	   else

No content for module {$moduleURI}

};

declare function docs:load-fundocs() {
	docs:load-internal-modules(),
	docs:load-external-modules()
};

declare function docs:load-documentation() {
	let $home := system:get-exist-home()
	let $dir :=
		if (doc-available(concat("file:///", $home, "/webapp/download.xml"))) then
			concat($home, "/webapp")
		else if(ends-with($home, "WEB-INF")) then
			substring-before($home, "WEB-INF")
		else
			concat($home)
	let $stored :=
		xdb:store-files-from-pattern($docs:COLLECTION, $dir, "*.xml", "text/xml")
	for $path in $stored
	return

{$path}

};

declare function docs:setup() as element(ul) {

    {
       	docs:configure(),
       	docs:load-fundocs(),
       	docs:load-documentation()
    }

};


Address #56 - Builtin Saxon functions: finish adding 9.8 and 9.9 function signatures.

xquery version "1.0";
(:~
 : Saxon extension functions
 : @see http://www.saxonica.com/html/documentation/functions/saxon
 :
 :)
module namespace saxon = "http://saxon.sf.net/";

declare namespace jt = "http://saxon.sf.net/java-type";
declare namespace xsl = "http://www.w3.org/1999/XSL/Transform";

declare namespace a = "http://reecedunn.co.uk/xquery/annotations";
declare namespace o = "http://reecedunn.co.uk/xquery/options";

declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:adjust-to-civil-time($in as xs:dateTime, $tz as xs:string) as xs:dateTime? external; (: reqs PE or EE :)
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:array-member($value as item()*) as jt:com.saxonica.functions.extfn.ArrayMemberValue external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:base64Binary-to-octets($input as xs:base64Binary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:base64Binary-to-string($input as xs:base64Binary?, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number() as xs:integer external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:compile-query($query as xs:string) as jt:net.sf.saxon.query.XQueryExpression external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:compile-stylesheet($stylesheet as document-node()) as jt.net.sf.saxon.PreparedStylesheet external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:decimal-divide($arg1 as xs:decimal?, $arg2 as xs:decimal, $precision as xs:integer) as xs:decimal? external;
declare %a:since("saxon/pe", "8.6.1") %a:since("saxon/ee", "8.6.1") function saxon:deep-equal($arg1 as item()*, $arg2 as item()*, $collation as xs:string?, $flags as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:discard-document($doc as document-node()) as document-node() external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:doc($href as xs:string, $options as map(*)) as document-node() external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:eval($stored-expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $param1 as item()*, $param2 as item()*, $param3 as item()*) as xs:double external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:evaluate($xpath as xs:string, $param1 as item()*, $param2 as item()*, $param3 as item()*) as item()* external;
declare %a:since("saxon/pe", "8.2") %a:since("saxon/ee", "8.2") function saxon:evaluate-node($node as node()) as item()* external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string, $ns as element()) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:function-annotations($fn as function(*)) as map(*)* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:get-pseudo-attribute($att as xs:string) as xs:string? external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:group-starting($input as item()*, $condition as function(item()) as xs:boolean) as array(item()*)+ external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:has-same-nodes($arg1 as node()*, $arg2 as node()*) as xs:boolean external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:hexBinary-to-octets($input as xs:hexBinary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:hexBinary-to-string($input as xs:hexBinary, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*, $key as function(*) (: $key [8.1] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.2] as function() [9.5] as function(*) :)) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:in-summer-time($date as xs:dateTime, $region as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.3") %a:since("saxon/ee", "8.3") %a:until("saxon/pe", "9.4") %a:until("saxon/ee", "9.4") function saxon:index($sequence as item()*, $expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $collation as xs:string) as jt:com.saxonica.expr.IndexedSequence external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:index($sequence as item()*, $function as function(item()) as xs:anyAtomicType* (: [9.5] as xs:integer  :)) as map(*) (: [8.3] as jt:com.saxonica.expr.IndexedSequence [9.5] as xs:double [9.7] as map(*) :) external;
declare %a:since("saxon/ee", "9.7") function saxon:is-defaulted($node as node()) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:is-whole-number($arg as xs:numeric?) as xs:boolean external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:last-modified($uri as xs:string? (: [9.0] () as document-uri($node)) [9.2] $uri as xs:string? :)) as xs:dateTime? external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") %a:until("saxon/pe", "9.1") %a:until("saxon/ee", "9.1") function saxon:last-modified($node as node()) as xs:dateTime? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*) as item() external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*, $test as function(*) (: [8.0] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.5] as function(*) :)) as item() external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number() as xs:integer external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*, $key as function(*) (: $key [8.0] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.2] as function() [9.5] as function(*) :)) as item()* external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:map-search($input as item()*, $key as xs:anyAtomicType) as map(*)* external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:map-search($input as item()*, $key as xs:anyAtomicType, $condition as function(item()) as xs:boolean) as map(*)* external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:message-count($errCode as xs:QName?) as xs:integer external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") %a:deprecated("saxon/pe", "9.2") %a:deprecated("saxon/ee", "9.2") function saxon:namespace-node($prefix as xs:string, $uri as xs:string) as namespace-node() external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:object-map($object as jt:java.lang.Object) as map(xs:string, function(*)) external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-base64Binary($octets as xs:integer*) as xs:base64Binary external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-hexBinary($octets as xs:integer*) as xs:hexBinary external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:parse-xml") function saxon:parse($xml as xs:string) as document-node() external;
declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:parse-html($html as xs:string) as document-node() external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path() as xs:string external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path($node as node()) as xs:string external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:pedigree($in as function(*)) as tuple(function(*), xs:anyAtomicType?, xs:integer?)? external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:print-stack() as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?, $params as node()*) as item()* external;
declare %a:since("saxon/pe", "9.7") %a:since("saxon/ee", "9.7") function saxon:read-binary-resource($uri as xs:string) as xs:base64Binary external;
declare %a:since("saxon/ee", "9.5") function saxon:schema() as function(*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:schema($kind as xs:string, $name as xs:QName) as function(*)? external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item()) as xs:boolean external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item(), $attachment as item()*) as xs:boolean external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as xs:string) as xs:string external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as element(xsl:output)) as xs:string external;
declare %a:since("saxon/pe", "8.9") %a:since("saxon/ee", "8.9") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*) as item()* external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*, $sort-key as function(item()) as xs:anyAtomicType) as item()* external;
declare %a:since("saxon/ee", "8.0") function saxon:stream($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-base64Binary($in as xs:string?, $encoding as xs:string) as xs:base64Binary? external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-hexBinary($in as xs:string?, $encoding as xs:string) as xs:hexBinary? external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:string-to-utf8($name as xs:string) as xs:integer* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:system-id() as xs:string external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:timestamp() as xs:dateTimeStamp external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node()) as document-node() external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node(), $params as item()*) as document-node() external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:type($item as item()?) as function(*)? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:type-annotation($item as item()?) as xs:QName? external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:unparsed-entities($doc as document-node()) as xs:string* external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*)) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*), $params as map(xs:string, item()*)) as map(xs:string, item()*)? external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:with-pedigree($in as function(*)) as function(*) external;

xquery version "1.0";
(:~
 : Saxon extension functions
 : @see http://www.saxonica.com/html/documentation/functions/saxon
 :
 :)
module namespace saxon = "http://saxon.sf.net/";

declare namespace jt = "http://saxon.sf.net/java-type";
declare namespace xsl = "http://www.w3.org/1999/XSL/Transform";

declare namespace a = "http://reecedunn.co.uk/xquery/annotations";
declare namespace o = "http://reecedunn.co.uk/xquery/options";

declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:adjust-to-civil-time($in as xs:dateTime, $tz as xs:string) as xs:dateTime? external; (: reqs PE or EE :)
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:array-member($value as item()*) as jt:com.saxonica.functions.extfn.ArrayMemberValue external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:base64Binary-to-octets($input as xs:base64Binary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:base64Binary-to-string($input as xs:base64Binary?, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number() as xs:integer external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:compile-query($query as xs:string) as jt:net.sf.saxon.query.XQueryExpression external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:compile-stylesheet($stylesheet as document-node()) as jt.net.sf.saxon.PreparedStylesheet external;
declare %a:since("saxon/pe", "9.3") %a:since("saxon/ee", "9.3") function saxon:current-mode-name() as xs:QName? external; (: @TODO the documentation claims that this was designed for XSLT :)
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:decimal-divide($arg1 as xs:decimal?, $arg2 as xs:decimal, $precision as xs:integer) as xs:decimal? external;
declare %a:since("saxon/pe", "8.6.1") %a:since("saxon/ee", "8.6.1") function saxon:deep-equal($arg1 as item()*, $arg2 as item()*, $collation as xs:string?, $flags as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:discard-document($doc as document-node()) as document-node() external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:eval($stored-expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $param1 as item()*, $param2 as item()*, $param3 as item()*) as xs:double external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:evaluate($xpath as xs:string, $param1 as item()*, $param2 as item()*, $param3 as item()*) as item()* external;
declare %a:since("saxon/pe", "8.2") %a:since("saxon/ee", "8.2") function saxon:evaluate-node($node as node()) as item()* external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string, $ns as element()) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:get-pseudo-attribute($att as xs:string) as xs:string? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:has-same-nodes($arg1 as node()*, $arg2 as node()*) as xs:boolean external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:hexBinary-to-octets($input as xs:hexBinary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:hexBinary-to-string($input as xs:hexBinary, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*, $key as function(*) (: $key [8.1] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.2] as function() [9.5] as function(*) :)) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:in-summer-time($date as xs:dateTime, $region as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.3") %a:since("saxon/ee", "8.3") %a:until("saxon/pe", "9.4") %a:until("saxon/ee", "9.4") function saxon:index($sequence as item()*, $expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $collation as xs:string) as jt:com.saxonica.expr.IndexedSequence external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:index($sequence as item()*, $function as function(item()) as xs:anyAtomicType* (: [9.5] as xs:integer  :)) as map(*) (: [8.3] as jt:com.saxonica.expr.IndexedSequence [9.5] as xs:double [9.7] as map(*) :) external;
declare %a:since("saxon/ee", "9.7") function saxon:is-defaulted($node as node()) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:is-whole-number($arg as xs:numeric?) as xs:boolean external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:last-modified($uri as xs:string? (: [9.0] () as document-uri($node)) [9.2] $uri as xs:string? :)) as xs:dateTime? external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") %a:until("saxon/pe", "9.1") %a:until("saxon/ee", "9.1") function saxon:last-modified($node as node()) as xs:dateTime? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*) as item() external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*, $test as function(*) (: [8.0] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.5] as function(*) :)) as item() external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number() as xs:integer external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*, $key as function(*) (: $key [8.0] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.2] as function() [9.5] as function(*) :)) as item()* external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") %a:deprecated("saxon/pe", "9.2") %a:deprecated("saxon/ee", "9.2") function saxon:namespace-node($prefix as xs:string, $uri as xs:string) as namespace-node() external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-base64Binary($octets as xs:integer*) as xs:base64Binary external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-hexBinary($octets as xs:integer*) as xs:hexBinary external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:parse-xml") function saxon:parse($xml as xs:string) as document-node() external;
declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:parse-html($html as xs:string) as document-node() external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path() as xs:string external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path($node as node()) as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:print-stack() as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?, $params as node()*) as item()* external;
declare %a:since("saxon/pe", "9.7") %a:since("saxon/ee", "9.7") function saxon:read-binary-resource($uri as xs:string) as xs:base64Binary external;
declare %a:since("saxon/ee", "9.5") function saxon:schema() as function(*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:schema($kind as xs:string, $name as xs:QName) as function(*)? external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item()) as xs:boolean external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item(), $attachment as item()*) as xs:boolean external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as xs:string) as xs:string external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as element(xsl:output)) as xs:string external;
declare %a:since("saxon/pe", "8.9") %a:since("saxon/ee", "8.9") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*) as item()* external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*, $sort-key as function(item()) as xs:anyAtomicType) as item()* external;
declare %a:since("saxon/ee", "8.0") function saxon:stream($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-base64Binary($in as xs:string?, $encoding as xs:string) as xs:base64Binary? external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-hexBinary($in as xs:string?, $encoding as xs:string) as xs:hexBinary? external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:string-to-utf8($name as xs:string) as xs:integer* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:system-id() as xs:string external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node()) as document-node() external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node(), $params as item()*) as document-node() external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:type($item as item()?) as function(*)? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:type-annotation($item as item()?) as xs:QName? external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:unparsed-entities($doc as document-node()) as xs:string* external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*)) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*), $params as map(xs:string, item()*)) as map(xs:string, item()*)? external;


[ignore] bibliographic demo: add "uuid-" prefix to generated mods ID to make it valid.

svn path=/trunk/eXist/; revision=13240

xquery version "1.0";

import module namespace style = "http://exist-db.org/mods-style" at "../../../modules/style.xqm";
import module namespace mods = "http://www.loc.gov/mods/v3" at "../modules/mods.xqm";
declare namespace xf="http://www.w3.org/2002/xforms";
declare namespace xforms="http://www.w3.org/2002/xforms";
declare namespace ev="http://www.w3.org/2001/xml-events";
declare namespace xlink="http://www.w3.org/1999/xlink";

let $title := 'MODS Record Editor'

(: get REST URL parameters :)
let $id-param := request:get-parameter('id', 'new')
let $show-all-string := request:get-parameter('show-all', 'false')
let $show-all := if ($show-all-string = 'true') then true() else false()

(: check if a host is specified for related item :)
let $host := request:get-parameter('host', ())

(: if no tab is specified, we default to the title tab :)
let $tab-id := request:get-parameter('tab-id', 'title')

(: display the label attached to the tab to the user :)
let $tab-data := concat($style:db-path-to-app, '/edit/tab-data.xml')
let $tab-label := doc($tab-data)/tabs/tab[tab-id=$tab-id]/label

(: if document type is specified then we will need to use that instance as the template :)
let $type := request:get-parameter('type', 'default')

(: look for an alternate data collection in the URL, else use the default mods data collection :)
let $user := request:get-parameter('user', '')

let $collection := request:get-parameter('collection', '')

let $data-collection :=
   if ($collection)
   then $collection
      else if ($user)
         then concat('/db/home/', $user, '/apps/mods/data')
         else '/db/org/library/apps/mods/data'

(: check to see if we have a  :)
let $new := if ($id-param = '' or $id-param = 'new')
        then true()
        else false()

(: if we do not have an incomming ID or it the ID is new then create one to use
   Note that for testing you can use the first five chars of the UUID substring(util:uuid(), 1, 5)
:)
let $id :=
   if ($new)
        then concat("uuid-", util:uuid())
        else $id-param

(: if we are creating a new record then we need to call get-instance.xq with new=true to tell it to get the entire template :)
let $create-new-from-template :=
   if ($new)
      then (
         (: copy the template into data and update it with a new UUID :)
         let $template-path :=
            if ($type='default')
               then concat($style:db-path-to-app, '/edit/new-instance.xml')
               else concat($style:db-path-to-app, '/edit/instances/', $type, '.xml')
         let $template := doc($template-path)
         let $new-file-name := concat($id, '.xml')

         (: uncomment the following line in for testing if you are not admin :)
         (: let $login := xmldb:login($data-collection, 'admin', ()) :)
         let $login := xmldb:login($data-collection, 'admin', 'his2RIen')
         (: store it in the right location :)
         let $store := xmldb:store($data-collection, $new-file-name, $template)
         let $new-file-path := concat($data-collection, '/', $new-file-name)

         (: note that we can not use "update replace" if we want to keep the default namespace :)
         return (
            update value doc($new-file-path)/mods:mods/@ID with $id,
            if ($host) then (
                update value doc($new-file-path)/mods:mods/mods:relatedItem/@xlink:href with $host,
                update value doc($new-file-path)/mods:mods/mods:relatedItem/@type with "host"
            ) else ()
         )
      ) else ()

(: this is the string we pass to instance id='save-data' src attribute :)
let $instance-src :=  concat('get-instance.xq?tab-id=', $tab-id, '&id=', $id, '&data=', $data-collection)

let $user := xmldb:get-current-user()

let $body-collection := concat($style:db-path-to-app, '/edit/body')

(: this is the part of the form that we need for this tab :)
let $form-body := collection($body-collection)/div[@tab-id = $tab-id]

let $style :=

let $model :=
    <xf:model>

       <xf:instance xmlns="http://www.loc.gov/mods/v3" src="{$instance-src}" id="save-data"/>

       <xf:instance xmlns="http://www.loc.gov/mods/v3" src="insert-templates.xml" id='insert-templates'/>

       <xf:instance xmlns="" id="code-tables" src="codes-for-tab.xq?tab-id={$tab-id}"/>

       <xf:bind nodeset="instance('save-data')/mods:titleInfo/mods:title" required="true()"/>

       <xf:bind nodeset="instance('save-data')/mods:recordInfo/mods:languageOfCataloging/mods:languageTerm" required="true()"/>
       <xf:bind nodeset="instance('save-data')/mods:recordInfo/mods:languageOfCataloging/mods:languageTerm/@authority" required="true()"/>
       <xf:bind nodeset="instance('save-data')/mods:recordInfo/mods:accessCondition/@type" required="true()"/>

       <xf:instance xmlns="" id="save-results">
          <data>
             <message>Form loaded OK.</message>
          </data>
       </xf:instance>

       <xf:submission id="save-submission" method="post"
          ref="instance('save-data')"
          action="save.xq?collection={$data-collection}" replace="instance"
          instance="save-results">
       </xf:submission>

       <xf:submission id="echo-post-submission" method="post"
          ref="instance('save-data')"
          action="echo-post.xq" replace="all">
       </xf:submission>

    </xf:model>

let $content :=

    editing record {$id} on the {$tab-label} tab

    {mods:tabs($tab-id, $id, $show-all, $data-collection)}

    <xf:submit submission="save-submission">
        <xf:label class="xforms-group-label-centered-general">Save</xf:label>
    </xf:submit>
    <xf:trigger>
        <xf:label class="xforms-group-label-centered-general">Save and Close</xf:label>
        <xf:action ev:event="DOMActivate">
            <xf:send submission="save-submission"/>
            <xf:load resource="../search/index.xml?reload=true" show="replace"/>
        </xf:action>
     </xf:trigger>

    {$form-body}

    View XML for the whole MODS record -
    View XML for the current tab

return style:assemble-form('', attribute {'mods:dummy'} {'dummy'}, $style, $model, $content, false())

xquery version "1.0";

import module namespace style = "http://exist-db.org/mods-style" at "../../../modules/style.xqm";
import module namespace mods = "http://www.loc.gov/mods/v3" at "../modules/mods.xqm";
declare namespace xf="http://www.w3.org/2002/xforms";
declare namespace xforms="http://www.w3.org/2002/xforms";
declare namespace ev="http://www.w3.org/2001/xml-events";
declare namespace xlink="http://www.w3.org/1999/xlink";

let $title := 'MODS Record Editor'

(: get REST URL parameters :)
let $id-param := request:get-parameter('id', 'new')
let $show-all-string := request:get-parameter('show-all', 'false')
let $show-all := if ($show-all-string = 'true') then true() else false()

(: check if a host is specified for related item :)
let $host := request:get-parameter('host', ())

(: if no tab is specified, we default to the title tab :)
let $tab-id := request:get-parameter('tab-id', 'title')

(: display the label attached to the tab to the user :)
let $tab-data := concat($style:db-path-to-app, '/edit/tab-data.xml')
let $tab-label := doc($tab-data)/tabs/tab[tab-id=$tab-id]/label

(: if document type is specified then we will need to use that instance as the template :)
let $type := request:get-parameter('type', 'default')

(: look for an alternate data collection in the URL, else use the default mods data collection :)
let $user := request:get-parameter('user', '')

let $collection := request:get-parameter('collection', '')

let $data-collection :=
   if ($collection)
   then $collection
      else if ($user)
         then concat('/db/home/', $user, '/apps/mods/data')
         else '/db/org/library/apps/mods/data'

(: check to see if we have a  :)
let $new := if ($id-param = '' or $id-param = 'new')
        then true()
        else false()

(: if we do not have an incomming ID or it the ID is new then create one to use
   Note that for testing you can use the first five chars of the UUID substring(util:uuid(), 1, 5)
:)
let $id :=
   if ($new)
        then util:uuid()
        else $id-param

(: if we are creating a new record then we need to call get-instance.xq with new=true to tell it to get the entire template :)
let $create-new-from-template :=
   if ($new)
      then (
         (: copy the template into data and update it with a new UUID :)
         let $template-path :=
            if ($type='default')
               then concat($style:db-path-to-app, '/edit/new-instance.xml')
               else concat($style:db-path-to-app, '/edit/instances/', $type, '.xml')
         let $template := doc($template-path)
         let $new-file-name := concat($id, '.xml')

         (: uncomment the following line in for testing if you are not admin :)
         (: let $login := xmldb:login($data-collection, 'admin', ()) :)
         let $login := xmldb:login($data-collection, 'admin', 'his2RIen')
         (: store it in the right location :)
         let $store := xmldb:store($data-collection, $new-file-name, $template)
         let $new-file-path := concat($data-collection, '/', $new-file-name)

         (: note that we can not use "update replace" if we want to keep the default namespace :)
         return (
            update value doc($new-file-path)/mods:mods/@ID with $id,
            if ($host) then (
                update value doc($new-file-path)/mods:mods/mods:relatedItem/@xlink:href with $host,
                update value doc($new-file-path)/mods:mods/mods:relatedItem/@type with "host"
            ) else ()
         )
      ) else ()

(: this is the string we pass to instance id='save-data' src attribute :)
let $instance-src :=  concat('get-instance.xq?tab-id=', $tab-id, '&id=', $id, '&data=', $data-collection)

let $user := xmldb:get-current-user()

let $body-collection := concat($style:db-path-to-app, '/edit/body')

(: this is the part of the form that we need for this tab :)
let $form-body := collection($body-collection)/div[@tab-id = $tab-id]

let $style :=

let $model :=
    <xf:model>

       <xf:instance xmlns="http://www.loc.gov/mods/v3" src="{$instance-src}" id="save-data"/>

       <xf:instance xmlns="http://www.loc.gov/mods/v3" src="insert-templates.xml" id='insert-templates'/>

       <xf:instance xmlns="" id="code-tables" src="codes-for-tab.xq?tab-id={$tab-id}"/>

       <xf:bind nodeset="instance('save-data')/mods:titleInfo/mods:title" required="true()"/>

       <xf:bind nodeset="instance('save-data')/mods:recordInfo/mods:languageOfCataloging/mods:languageTerm" required="true()"/>
       <xf:bind nodeset="instance('save-data')/mods:recordInfo/mods:languageOfCataloging/mods:languageTerm/@authority" required="true()"/>
       <xf:bind nodeset="instance('save-data')/mods:recordInfo/mods:accessCondition/@type" required="true()"/>

       <xf:instance xmlns="" id="save-results">
          <data>
             <message>Form loaded OK.</message>
          </data>
       </xf:instance>

       <xf:submission id="save-submission" method="post"
          ref="instance('save-data')"
          action="save.xq?collection={$data-collection}" replace="instance"
          instance="save-results">
       </xf:submission>

       <xf:submission id="echo-post-submission" method="post"
          ref="instance('save-data')"
          action="echo-post.xq" replace="all">
       </xf:submission>

    </xf:model>

let $content :=

    editing record {$id} on the {$tab-label} tab

    {mods:tabs($tab-id, $id, $show-all, $data-collection)}

    <xf:submit submission="save-submission">
        <xf:label class="xforms-group-label-centered-general">Save</xf:label>
    </xf:submit>
    <xf:trigger>
        <xf:label class="xforms-group-label-centered-general">Save and Close</xf:label>
        <xf:action ev:event="DOMActivate">
            <xf:send submission="save-submission"/>
            <xf:load resource="../search/index.xml?reload=true" show="replace"/>
        </xf:action>
     </xf:trigger>

    {$form-body}

    View XML for the whole MODS record -
    View XML for the current tab

return style:assemble-form('', attribute {'mods:dummy'} {'dummy'}, $style, $model, $content, false())


Signature resilient to missing query

Signature resilient to missing query

We've found out (but not clearly identified) that with some combinations of browsers/proxies the body is not an empty string "" but rather an empty sequence. This is causing error when opening the database view of the dba.
We propose to make the query parameter optional.

(:~
 : Query resources.
 :
 : @author Christian Grün, BaseX Team 2005-21, BSD License
 :)
module namespace dba = 'dba/databases';

import module namespace util = 'dba/util' at '../../lib/util.xqm';

(:~
 : Runs a query on a document and returns the result as string.
 : @param  $name      name of database
 : @param  $resource  resource
 : @param  $query     query
 : @return result string
 :)
declare
  %rest:POST('{$query}')
  %rest:path('/dba/db-query')
  %rest:query-param('name',     '{$name}')
  %rest:query-param('resource', '{$resource}')
  %rest:single
  %output:method('text')
function dba:db-query(
  $name      as xs:string,
  $resource  as xs:string,
  $query     as xs:string?
) as xs:string {
  util:query(if($query) then $query else '.', db:open($name, $resource))
};

(:~
 : Query resources.
 :
 : @author Christian Grün, BaseX Team 2005-21, BSD License
 :)
module namespace dba = 'dba/databases';

import module namespace util = 'dba/util' at '../../lib/util.xqm';

(:~
 : Runs a query on a document and returns the result as string.
 : @param  $name      name of database
 : @param  $resource  resource
 : @param  $query     query
 : @return result string
 :)
declare
  %rest:POST('{$query}')
  %rest:path('/dba/db-query')
  %rest:query-param('name',     '{$name}')
  %rest:query-param('resource', '{$resource}')
  %rest:single
  %output:method('text')
function dba:db-query(
  $name      as xs:string,
  $resource  as xs:string,
  $query     as xs:string
) as xs:string {
  util:query(if($query) then $query else '.', db:open($name, $resource))
};


[apidoc] Support generating the MarkLogic 6.0 apidoc function signatures.

(:
 : Copyright (C) 2020 Reece H. Dunn
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
 :)
xquery version "3.1";

declare namespace apidoc = "http://marklogic.com/xdmp/apidoc";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace xhtml = "http://www.w3.org/1999/xhtml";

declare variable $apidoc as element(apidoc:apidoc) :=
    typeswitch (.)
    case xs:string return fn:parse-xml(.)/element()
    case document-node() return ./element()
    default return .;

declare variable $language as xs:string := "xquery"; (: xquery | rest :)

(: namespaces -------------------------------------------------------------- :)

declare variable $module-namespaces := map:merge(
    for $import in $apidoc//apidoc:module/apidoc:summary/(*:p|*:pre)
    let $match := fn:analyze-string(($import/*:code, $import)[1], "import module (namespace\s*([a-z0-9]+)\s*=\s*)?""([^""]+)""")/fn:match[1]
    let $prefix := ($match//fn:group[@nr = "2"]/string(), $import/ancestor::apidoc:module/@lib)[1]
    let $namespace := $match/fn:group[@nr = "3"]/string()
    where exists($namespace)
    return map:entry($prefix, $namespace)
);

declare variable $xquery-namespaces := map {
    "local": "http://www.w3.org/2005/xquery-local-functions",
    "fn": "http://www.w3.org/2005/xpath-functions",
    "xml": "http://www.w3.org/XML/1998/namespace",
    "xs": "http://www.w3.org/2001/XMLSchema",
    "xsi": "http://www.w3.org/2001/XMLSchema-instance"
};

declare variable $marklogic-5-builtin := map {
    "cts": "http://marklogic.com/cts",
    "dbg": "http://marklogic.com/xdmp/dbg",
    "dir": "http://marklogic.com/xdmp/directory",
    "error": "http://marklogic.com/xdmp/error",
    "map": "http://marklogic.com/xdmp/map",
    "math": "http://marklogic.com/xdmp/math",
    "prof": "http://marklogic.com/xdmp/profile",
    "sec": "http://marklogic.com/security",
    "spell": "http://marklogic.com/xdmp/spell",
    "xdmp": "http://marklogic.com/xdmp"
};

declare variable $marklogic-additional := map {
    "as": "http://marklogic.com/xdmp/assignments",
    "db": "http://marklogic.com/xdmp/database",
    "dg": "xdmp:document-get",
    "cl": "http://marklogic.com/xdmp/clusters",
    "exsl": "http://exslt.org/common",
    "gr": "http://marklogic.com/xdmp/group",
    "xdt": "http://www.w3.org/2004/10/xpath-datatypes",
    "xi": "http://www.w3.org/2001/XInclude",
    "mt": "http://marklogic.com/xdmp/mimetypes",
    "pkg": "http://marklogic.com/manage/package",
    "s": "http://www.w3.org/2009/xpath-functions/analyze-string",
    "x509": "http://marklogic.com/xdmp/x509"
};

declare variable $namespaces := map:merge((
    $module-namespaces,
    $xquery-namespaces,
    $marklogic-5-builtin,
    $marklogic-additional,
    ()
));

(: functions --------------------------------------------------------------- :)

(: Several functions in the apidocs have duplicate parameter names in some versions, so fix these. :)
declare variable $param-fixes := map {
    "fn:subtract-dateTimes-yielding-dayTimeDuration": ("srcval1", "srcval2"),
    "fn:subtract-dateTimes-yielding-yearMonthDuration": ("srcval1", "srcval2"),
    "math:fmod": ("x", "y"),
    "math:rank": ("arg1", "arg2", "options")
};

declare variable $functions as element(apidoc:function)* := $apidoc//apidoc:function[
    local:function-language(.) = $language and not(@name = "")
];

declare function local:function-language($function as element(apidoc:function)) as xs:string {
    let $bucket := $function/@bucket
    return switch ($bucket)
    case "REST Resources API" return "rest"
    default return "xquery"
};

declare function local:function-name($function as element(apidoc:function)) as xs:string {
    ``[`{$function/@lib}`:`{$function/@name}`]``
};

declare function local:function-parameters($function as element(apidoc:function)) as xs:string* {
    let $names as xs:string* :=
        let $names := map:get($param-fixes, local:function-name($function))
        return if (exists($names)) then
            $names
        else
            $function/apidoc:params/apidoc:param/@name/string()
    return if (count($names) != count(distinct-values($names))) then
        fn:error(xs:QName("err:XQST0039"),``[Duplicate parameter name in `{local:function-name($function)}`]``)
    else
        $names
};

declare function local:function-parameter($function as element(apidoc:function), $name as xs:string) as element(apidoc:param) {
    let $names := map:get($param-fixes, local:function-name($function))
    return if (exists($names)) then
        let $i := fn:index-of($names, $name)
        return $function/apidoc:params/apidoc:param[$i]
    else
        $function/apidoc:params/apidoc:param[@name = $name]
};

declare function local:function-parameter-type($function as element(apidoc:function), $name as xs:string) as xs:string {
    if ($function/@lib = "exsl" and $function/@name = "object-type") then
        "item()*" (: MarkLogic 7 and earlier docs have this as 'atomic type'. :)
    else
        let $type := local:function-parameter($function, $name)/@type/string()
        return switch ($type)
        case "binary())" return "binary()"
        case "xs:string)" return "xs:string"
        default return replace($type, ",\.\.\.", "...")
};

declare function local:function-return-type($function as element(apidoc:function)) as xs:string {
    let $type := $function/apidoc:return/string()
    return switch ($type)
    case "An XML representation of the certificate." return "element()?"
    case "element())" return "element()"
    case "xs:unsignedLong)" return "xs:unsignedLong"
    default return $type
};

declare function local:function-xquery-signatures($function as element(apidoc:function)) as xs:string* {
    let $name := local:function-name($function)
    let $params :=
        for $name in local:function-parameters($function)
        let $type := local:function-parameter-type($function, $name)
        return ``[$`{$name}` as `{$type}`]``
    let $type := local:function-return-type($function)
    return ``[declare function `{$name}`(`{string-join($params, ", ")}`) as `{$type}` external;]``
};

(: query ------------------------------------------------------------------- :)

for $prefix in map:keys($namespaces)
let $namespace := map:get($namespaces, $prefix)
order by $prefix
return ``[declare namespace `{$prefix}` = "`{$namespace}`";]``
,
for $function in $functions
order by $function/@lib, $function/@name
return local:function-xquery-signatures($function)

(:
 : Copyright (C) 2020 Reece H. Dunn
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
 :)
xquery version "3.1";

declare namespace apidoc = "http://marklogic.com/xdmp/apidoc";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace xhtml = "http://www.w3.org/1999/xhtml";

declare variable $apidoc as element(apidoc:apidoc) :=
    typeswitch (.)
    case xs:string return fn:parse-xml(.)/element()
    case document-node() return ./element()
    default return .;

declare variable $language as xs:string := "xquery"; (: xquery | rest :)

(: namespaces -------------------------------------------------------------- :)

declare variable $module-namespaces := map:merge(
    for $import in $apidoc//apidoc:module/apidoc:summary/(*:p|*:pre)
    let $match := fn:analyze-string(($import/*:code, $import)[1], "import module (namespace\s*([a-z0-9]+)\s*=\s*)?""([^""]+)""")/fn:match[1]
    let $prefix := ($match//fn:group[@nr = "2"]/string(), $import/ancestor::apidoc:module/@lib)[1]
    let $namespace := $match/fn:group[@nr = "3"]/string()
    where exists($namespace)
    return map:entry($prefix, $namespace)
);

declare variable $xquery-namespaces := map {
    "local": "http://www.w3.org/2005/xquery-local-functions",
    "fn": "http://www.w3.org/2005/xpath-functions",
    "xml": "http://www.w3.org/XML/1998/namespace",
    "xs": "http://www.w3.org/2001/XMLSchema",
    "xsi": "http://www.w3.org/2001/XMLSchema-instance"
};

declare variable $marklogic-5-builtin := map {
    "cts": "http://marklogic.com/cts",
    "dbg": "http://marklogic.com/xdmp/dbg",
    "dir": "http://marklogic.com/xdmp/directory",
    "error": "http://marklogic.com/xdmp/error",
    "map": "http://marklogic.com/xdmp/map",
    "math": "http://marklogic.com/xdmp/math",
    "prof": "http://marklogic.com/xdmp/profile",
    "sec": "http://marklogic.com/security",
    "spell": "http://marklogic.com/xdmp/spell",
    "xdmp": "http://marklogic.com/xdmp"
};

declare variable $marklogic-additional := map {
    "as": "http://marklogic.com/xdmp/assignments",
    "db": "http://marklogic.com/xdmp/database",
    "dg": "xdmp:document-get",
    "cl": "http://marklogic.com/xdmp/clusters",
    "exsl": "http://exslt.org/common",
    "gr": "http://marklogic.com/xdmp/group",
    "xdt": "http://www.w3.org/2004/10/xpath-datatypes",
    "xi": "http://www.w3.org/2001/XInclude",
    "mt": "http://marklogic.com/xdmp/mimetypes",
    "pkg": "http://marklogic.com/manage/package",
    "s": "http://www.w3.org/2009/xpath-functions/analyze-string",
    "x509": "http://marklogic.com/xdmp/x509"
};

declare variable $namespaces := map:merge((
    $module-namespaces,
    $xquery-namespaces,
    $marklogic-5-builtin,
    $marklogic-additional,
    ()
));

(: functions --------------------------------------------------------------- :)

(: Several functions in the apidocs have duplicate parameter names in some versions, so fix these. :)
declare variable $param-fixes := map {
    "fn:subtract-dateTimes-yielding-dayTimeDuration": ("srcval1", "srcval2"),
    "fn:subtract-dateTimes-yielding-yearMonthDuration": ("srcval1", "srcval2"),
    "math:fmod": ("x", "y"),
    "math:rank": ("arg1", "arg2", "options")
};

declare variable $functions as element(apidoc:function)* := $apidoc//apidoc:function[
    local:function-language(.) = $language and not(@name = "")
];

declare function local:function-language($function as element(apidoc:function)) as xs:string {
    let $bucket := $function/@bucket
    return switch ($bucket)
    case "REST Resources API" return "rest"
    default return "xquery"
};

declare function local:function-name($function as element(apidoc:function)) as xs:string {
    ``[`{$function/@lib}`:`{$function/@name}`]``
};

declare function local:function-parameters($function as element(apidoc:function)) as xs:string* {
    let $names as xs:string* :=
        let $names := map:get($param-fixes, local:function-name($function))
        return if (exists($names)) then
            $names
        else
            $function/apidoc:params/apidoc:param/@name/string()
    return if (count($names) != count(distinct-values($names))) then
        fn:error(xs:QName("err:XQST0039"),``[Duplicate parameter name in `{local:function-name($function)}`]``)
    else
        $names
};

declare function local:function-parameter($function as element(apidoc:function), $name as xs:string) as element(apidoc:param) {
    let $names := map:get($param-fixes, local:function-name($function))
    return if (exists($names)) then
        let $i := fn:index-of($names, $name)
        return $function/apidoc:params/apidoc:param[$i]
    else
        $function/apidoc:params/apidoc:param[@name = $name]
};

declare function local:function-parameter-type($function as element(apidoc:function), $name as xs:string) as xs:string {
    if ($function/@lib = "exsl" and $function/@name = "object-type") then
        "item()*" (: MarkLogic 7 and earlier docs have this as 'atomic type'. :)
    else
        let $type := local:function-parameter($function, $name)/@type/string()
        return replace($type, ",\.\.\.", "...")
};

declare function local:function-return-type($function as element(apidoc:function)) as xs:string {
    let $type := $function/apidoc:return/string()
    return switch ($type)
    case "An XML representation of the certificate." return "element()?"
    case "element())" return "element()"
    case "xs:unsignedLong)" return "xs:unsignedLong"
    default return $type
};

declare function local:function-xquery-signatures($function as element(apidoc:function)) as xs:string* {
    let $name := local:function-name($function)
    let $params :=
        for $name in local:function-parameters($function)
        let $type := local:function-parameter-type($function, $name)
        return ``[$`{$name}` as `{$type}`]``
    let $type := local:function-return-type($function)
    return ``[declare function `{$name}`(`{string-join($params, ", ")}`) as `{$type}` external;]``
};

(: query ------------------------------------------------------------------- :)

for $prefix in map:keys($namespaces)
let $namespace := map:get($namespaces, $prefix)
order by $prefix
return ``[declare namespace `{$prefix}` = "`{$namespace}`";]``
,
for $function in $functions
order by $function/@lib, $function/@name
return local:function-xquery-signatures($function)


Don't run schemas in build directory through make_xqdoc test.

(:
 : Copyright 2006-2009 The FLWOR Foundation.
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
:)
import module namespace file = "http://expath.org/ns/file";

import module namespace xqdoc       = "http://www.zorba-xquery.com/modules/xqdoc";
import module namespace batch       = "http://www.zorba-xquery.com/modules/xqdoc/batch";
import module namespace fetch = "http://www.zorba-xquery.com/modules/fetch";
import module namespace xqdoc-html  = "http://www.zorba-xquery.com/xqdoc-html" at "xqdoc-html.xqy";

declare namespace xqd = "http://www.xqdoc.org/1.0";
declare namespace z   = "http://zorba.io/manifest";
declare namespace xs  = "http://www.w3.org/2001/XMLSchema";

declare variable $zorbaManifestPath   as xs:string external;
declare variable $xhtmlRequisitesPath as xs:string external;
declare variable $xqdocBuildPath      as xs:string external;
declare variable $zorbaVersion        as xs:string external;

declare variable $slash := file:directory-separator();
declare variable $serXML:= <output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
                             <output:method   value="xml" />
                             <output:encoding value="UTF-8"/>
                           </output:serialization-parameters>;

declare %private function local:write-Doxygen(
  $content,
  $name as xs:string,
  $uri as xs:string?,
  $type as xs:string){
fn:serialize(<doxygen><compounddef id="{$name}-{$type}" kind="{$type}">
               <detaileddescription><para><h3>{concat("Content of ", $name, " " , $type)}</h3><programlisting type="{$type}">{fn:serialize($content,$serXML)}</programlisting></para></detaileddescription>
             </compounddef></doxygen>,$serXML)
};

(: Delete previous version of the documentation :)
if(file:exists($xqdocBuildPath))
then file:delete($xqdocBuildPath);
else ();

(: Copy Schemas :)
file:create-directory($xqdocBuildPath || $slash ||  "schemas");
file:create-directory($xqdocBuildPath || $slash || "xml");
let $base := $xhtmlRequisitesPath || $slash || ".." || $slash || ".." || $slash || ".." || $slash
let $dest := $xqdocBuildPath || $slash || "xml"
for $schema in file:list($base, true(), "*.xsd")
where not(ends-with($schema, ".ent.xsd"))
  and not(ends-with($schema, ".dtd.xsd"))
  and not(contains($schema, "URI_PATH"))
let $schema-doc := doc($base || $slash || trace($schema, "schema"))
let $target-uri := $schema-doc/xs:schema/@targetNamespace/string()
let $name := replace(replace($target-uri, "http://", ""), "/", "_")
return {
  (file:write-text($xqdocBuildPath || $slash || "schemas" || $slash || $name || ".xsd", $schema-doc),
  file:write-text($dest || $slash || replace(replace($target-uri, "http://", ""), "/", "_") || "-schema.xml",
                  local:write-Doxygen($schema-doc, $name, $target-uri, "schema"))
  )
};

file:create-directory($xqdocBuildPath || $slash ||  "examples");
variable $manifest := parse-xml(file:read-text($zorbaManifestPath));
for $module in $manifest/z:manifest/z:module
let $uri := $module/z:uri/text()
let $xqdoc := xqdoc:xqdoc($uri)
let $module-name := tokenize($uri,"/")[last()]
return {
  (: Copy Examples :)
  for $example in $xqdoc//xqd:custom[@tag="example"]/text()
  let $source := $module/z:projectRoot/text() || $slash || $example
  let $test-name := trace(tokenize($source,"/")[last()], "example-name")
  let $destination := $xqdocBuildPath || $slash ||  "examples" || $slash || concat($module-name, "_", $test-name)
  let $dest := $xqdocBuildPath || $slash ||  "xml" || $slash || concat($module-name, "_", substring-before($test-name,".xq")) || "-example.xml"
  return {
    file:copy($source, $destination);
    file:write-text($dest,
                   local:write-Doxygen(file:read-text($source),$test-name, $uri, "example"));
  }
}

(: XQDoc Batch :)
let $static-folders := ("js", "css", "images")
let $static-folders := for $static in $static-folders return $xhtmlRequisitesPath || $slash || $static
let $template := parse-xml(file:read-text($xhtmlRequisitesPath || $slash || "template.xml"))/*
let $output-folder := $xqdocBuildPath
let $modules := xqdoc-html:modules($manifest)
return batch:build-xqdoc($output-folder, $static-folders, $template, $modules);

(: Copy modules :)
for $module in $manifest/z:manifest/z:module
let $uri := $module/z:uri/text()
let $module := fetch:content($uri, "MODULE")
return
  file:write-text($xqdocBuildPath || $slash || "xml" || $slash || replace(substring-after($uri, "http://"),"/","_") || "-module.xml",
                  local:write-Doxygen($module, tokenize($uri,"/")[last()], $uri, "module"));

trace("","XQDoc generated successfully!");

(:
 : Copyright 2006-2009 The FLWOR Foundation.
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
:)
import module namespace file = "http://expath.org/ns/file";

import module namespace xqdoc       = "http://www.zorba-xquery.com/modules/xqdoc";
import module namespace batch       = "http://www.zorba-xquery.com/modules/xqdoc/batch";
import module namespace fetch = "http://www.zorba-xquery.com/modules/fetch";
import module namespace xqdoc-html  = "http://www.zorba-xquery.com/xqdoc-html" at "xqdoc-html.xqy";

declare namespace xqd = "http://www.xqdoc.org/1.0";
declare namespace z   = "http://zorba.io/manifest";
declare namespace xs  = "http://www.w3.org/2001/XMLSchema";

declare variable $zorbaManifestPath   as xs:string external;
declare variable $xhtmlRequisitesPath as xs:string external;
declare variable $xqdocBuildPath      as xs:string external;
declare variable $zorbaVersion        as xs:string external;

declare variable $slash := file:directory-separator();
declare variable $serXML:= <output:serialization-parameters xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
                             <output:method   value="xml" />
                             <output:encoding value="UTF-8"/>
                           </output:serialization-parameters>;

declare %private function local:write-Doxygen(
  $content,
  $name as xs:string,
  $uri as xs:string?,
  $type as xs:string){
fn:serialize(<doxygen><compounddef id="{$name}-{$type}" kind="{$type}">
               <detaileddescription><para><h3>{concat("Content of ", $name, " " , $type)}</h3><programlisting type="{$type}">{fn:serialize($content,$serXML)}</programlisting></para></detaileddescription>
             </compounddef></doxygen>,$serXML)
};

(: Delete previous version of the documentation :)
if(file:exists($xqdocBuildPath))
then file:delete($xqdocBuildPath);
else ();

(: Copy Schemas :)
file:create-directory($xqdocBuildPath || $slash ||  "schemas");
file:create-directory($xqdocBuildPath || $slash || "xml");
let $base := $xhtmlRequisitesPath || $slash || ".." || $slash || ".." || $slash || ".." || $slash
let $dest := $xqdocBuildPath || $slash || "xml"
for $schema in file:list($base, true(), "*.xsd")
where not(ends-with($schema, ".ent.xsd")) and not(ends-with($schema, ".dtd.xsd"))
let $schema-doc := doc($base || $slash || trace($schema, "schema"))
let $target-uri := $schema-doc/xs:schema/@targetNamespace/string()
let $name := replace(replace($target-uri, "http://", ""), "/", "_")
return {
  (file:write-text($xqdocBuildPath || $slash || "schemas" || $slash || $name || ".xsd", $schema-doc),
  file:write-text($dest || $slash || replace(replace($target-uri, "http://", ""), "/", "_") || "-schema.xml",
                  local:write-Doxygen($schema-doc, $name, $target-uri, "schema"))
  )
};

file:create-directory($xqdocBuildPath || $slash ||  "examples");
variable $manifest := parse-xml(file:read-text($zorbaManifestPath));
for $module in $manifest/z:manifest/z:module
let $uri := $module/z:uri/text()
let $xqdoc := xqdoc:xqdoc($uri)
let $module-name := tokenize($uri,"/")[last()]
return {
  (: Copy Examples :)
  for $example in $xqdoc//xqd:custom[@tag="example"]/text()
  let $source := $module/z:projectRoot/text() || $slash || $example
  let $test-name := trace(tokenize($source,"/")[last()], "example-name")
  let $destination := $xqdocBuildPath || $slash ||  "examples" || $slash || concat($module-name, "_", $test-name)
  let $dest := $xqdocBuildPath || $slash ||  "xml" || $slash || concat($module-name, "_", substring-before($test-name,".xq")) || "-example.xml"
  return {
    file:copy($source, $destination);
    file:write-text($dest,
                   local:write-Doxygen(file:read-text($source),$test-name, $uri, "example"));
  }
}

(: XQDoc Batch :)
let $static-folders := ("js", "css", "images")
let $static-folders := for $static in $static-folders return $xhtmlRequisitesPath || $slash || $static
let $template := parse-xml(file:read-text($xhtmlRequisitesPath || $slash || "template.xml"))/*
let $output-folder := $xqdocBuildPath
let $modules := xqdoc-html:modules($manifest)
return batch:build-xqdoc($output-folder, $static-folders, $template, $modules);

(: Copy modules :)
for $module in $manifest/z:manifest/z:module
let $uri := $module/z:uri/text()
let $module := fetch:content($uri, "MODULE")
return
  file:write-text($xqdocBuildPath || $slash || "xml" || $slash || replace(substring-after($uri, "http://"),"/","_") || "-module.xml",
                  local:write-Doxygen($module, tokenize($uri,"/")[last()], $uri, "module"));

trace("","XQDoc generated successfully!");


Formatted according to XQDocs, added overall description drawn from the call.xql example.

svn path=/trunk/eXist/; revision=14025

(:~ Basic XQuery equivalents of map, fold, and filter functions adapted from
 :  the standard library of the Scheme programming language.  Demonstrates the
 :  use of higher-order functions in eXist.
 :)
module namespace seq="http://exist-db.org/xquery/sequences";

import module namespace util="http://exist-db.org/xquery/util";

(:~ Applies $func to the items
 :  of two sequences and returns the results as
 :  a new sequence. Both input sequences should
 :  have the same length.
 :)
declare function seq:map($func as function, $seqA as item()*, $seqB as item()*)
as item()* {
	if(count($seqA) != count($seqB)) then
		error("The sequences passed to seq:map should have equal length.")
	else
    	for $a at $i in $seqA
    	let $b := $seqB[$i]
    	return
        	util:call($func, $a, $b)
};

(:~	Calls $func for all items in the sequence. For example, if
 :  the sequence is (1, 2, 3), $func will be called with arguments
 :  (1, 2) and (3, 3).
 :)
declare function seq:fold($func as function, $seq as item()*, $start as item()) {
	if(empty($seq)) then
		$start
	else
		seq:fold($func, remove($seq, 1), util:call($func, $start, $seq[1]))
};

(:~ Filters the passed sequence by calling $func for every
 :  item. All items for which $func returns true are copied
 :  to the output sequence, items for which it returns false
 :  are skipped.
 :)
declare function seq:filter($func as function, $seq as item()*)
as item()* {
	for $i in $seq
	return
		if(util:call($func, $i)) then
			$i
		else
			()
};

module namespace seq="http://exist-db.org/xquery/sequences";

import module namespace util="http://exist-db.org/xquery/util";

(: 	Applies $func element-wise to the elements
	of two sequences and returns the results as
	a new sequence. Both input sequences should
	have the same length.
:)
declare function seq:map($func as function, $seqA as item()*, $seqB as item()*)
as item()* {
	if(count($seqA) != count($seqB)) then
		error("The sequences passed to seq:map should have equal length.")
	else
    	for $a at $i in $seqA
    	let $b := $seqB[$i]
    	return
        	util:call($func, $a, $b)
};

(:	Calls $func for all items in the sequence. For example, if
	the sequence is (1, 2, 3), $func will be called with arguments
	(1, 2) and (3, 3).
:)
declare function seq:fold($func as function, $seq as item()*, $start as item()) {
	if(empty($seq)) then
		$start
	else
		seq:fold($func, remove($seq, 1), util:call($func, $start, $seq[1]))
};

(:	Filters the passed sequence by calling $func for every
	item. All items for which $func returns true are copied
	to the output sequence, items for which it returns false
	are skipped.
:)
declare function seq:filter($func as function, $seq as item()*)
as item()* {
	for $i in $seq
	return
		if(util:call($func, $i)) then
			$i
		else
			()
};