[bugfix] fixed links to resources in collection browser. Did not work if admin web app was stored in the database.

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

xquery version "1.0";
(: $Id$ :)
(:
    Module: display and browse collections.
:)

module namespace browse="http://exist-db.org/xquery/admin-interface/browse";

declare namespace request="http://exist-db.org/xquery/request";
declare namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace v="http://exist-db.org/versioning";

import module namespace date="http://exist-db.org/xquery/admin-interface/date" at "dates.xqm";

(:
    Main function: outputs the page.
:)
declare function browse:main() as element()
{
    let $colName := request:get-parameter("collection", "/db") return

            { browse:process-action($colName) }

Browsing Collection: {xdb:decode-uri(xs:anyURI($colName))}

            <form method="POST" enctype="multipart/form-data">
                {
                    browse:display-collection($colName)
                }

<input type="submit" name="action" value="Remove Selected"/>

                        <input type="submit" name="action" value="Create Collection"/>
                        New collection:

                        <input type="text" name="create" size="40"/>

                        <input type="submit" name="action" value="Upload"/>
                        <input type="file" size="30" name="upload"/>
                        Store as:

                        <input type="text" name="name" size="20"/>

                <input type="hidden" name="collection" value="{$colName}"/>
                <input type="hidden" name="panel" value="browse"/>
            </form>

};

(:
    Process an action.
:)
declare function browse:process-action($colName as xs:string) as element()*
{
    let $action := request:get-parameter("action", ()) return
        util:catch("java.lang.Exception",
            if($action eq "Remove Selected") then
            (
                browse:remove()
            )
            else if($action eq "Create Collection") then
            (
                browse:create-collection($colName)
            )
            else if($action eq "Store") then
            (
                browse:store($colName)
            )
            else if($action eq "Upload") then
            (
                browse:upload($colName)
            )else(),

                An error occurred while processing the action:

                {$util:exception-message}

        )
};

(:
    Store uploaded content.
:)
declare function browse:upload($colName as xs:string) as element()
{
    let $name := request:get-parameter("name", ()),
    $docName := if($name) then $name else request:get-uploaded-file-name("upload"),
    $file := request:get-uploaded-file("upload") return

Actions:

Storing uploaded content to: {$docName}

                {
                    xdb:decode-uri(xs:anyURI(xdb:store($colName, xdb:encode-uri($docName), $file)))
                }

};

(:
    Store files from an URI.

    Allowing this opens a security whole as a user can
    upload arbitrary files on the server if the process is running
    as root.
:)
declare function browse:store($colName as xs:string) as element()
{
    let $uri := request:get-parameter("uri", ()),
    $path := if(starts-with($uri, "file:")) then $uri else concat("file:", $uri),
    $docName := request:get-parameter("name", ()) return

Actions:

Storing resources from URI: {$path}

                {
                    xdb:store($colName, $docName, xs:anyURI($path))
                }

};

(:
    Remove a set of resources.
:)
declare function browse:remove() as element()
{
    let $resources := request:get-parameter("resource", ()) return

Actions:

                {
                    for $resource in $resources
                    return
                        browse:remove-resource($resource)
                }

};

(:
    Remove a resource.
:)
declare function browse:remove-resource($resource as xs:string) as element()*
{
    let $isBinary := util:binary-doc-available($resource),
    $doc := if ($isBinary) then $resource else doc($resource) return

        if($doc)then
        (

Removing document: {xdb:decode-uri(xs:anyURI($resource))} ...
,
            xdb:remove(util:collection-name($doc), util:document-name($doc))
        )
        else
        (

Removing collection: {xdb:decode-uri(xs:anyURI($resource))} ...
,
            xdb:remove($resource)
        )
};

(:
    Create a collection.
:)
declare function browse:create-collection($parentColName as xs:string) as element()
{
    let $newcol := request:get-parameter("create", ()) return

Actions:

            {
                if($newcol) then
                (
                    let $col := xdb:create-collection($parentColName, xdb:encode-uri($newcol)) return

Created collection: {xdb:decode-uri(xs:anyURI(util:collection-name($col)))}.

                )
                else
                (

No name specified for new collection!

                )
            }

};

(:
    Display the contents of a collection in a table view.
:)
declare function browse:display-collection($colName as xs:string) as element()
{

            Name
            Permissions
            Owner
            Group
            Created
            Modified
            Size (KB)
			Revision

            Up

        {
            browse:display-child-collections($colName),
            browse:display-child-resources($colName)
        }

};

declare function browse:display-child-collections($colName as xs:string) as element()*
{
    for $child in xdb:get-child-collections($colName)
        let $path := concat($colName, '/', $child),
        $created := xdb:created($path)
    order by $child return

            <input type="checkbox" name="resource" value="{$path}"/>
            {xdb:decode-uri(xs:anyURI($child))}
            {xdb:permissions-to-string(xdb:get-permissions($path))}
            {xdb:get-owner($path)}
            {xdb:get-group($path)}
            {date:format-dateTime($created)}

};

declare function browse:display-child-resources($colName as xs:string) as element()*
{
    for $child in xdb:get-child-resources($colName)
    let $restUri := concat(request:get-context-path(), '/rest')
    order by $child
	return

            <input type="checkbox" name="resource" value="{$colName}/{$child}"/>
            {xdb:decode-uri(xs:anyURI($child))}
            {xdb:permissions-to-string(xdb:get-permissions($colName, $child))}
            {xdb:get-owner($colName, $child)}
            {xdb:get-group($colName, $child)}
            {date:format-dateTime(xdb:created($colName, $child))}
            {date:format-dateTime(xdb:last-modified($colName, $child))}
            {fn:ceiling(xdb:size($colName, $child) div 1024)}

				{browse:last-revision($colName, $child)//v:properties/v:revision/string()}

};

declare function browse:last-revision($collection as xs:string, $resource as xs:string) {
	let $vCollection := concat("/db/system/versions", $collection)
	let $versions :=
		for $version in collection($vCollection)/v:version[
			v:properties[v:document = $resource]
		]
		order by xs:long($version/v:properties/v:revision) descending
		return $version
	return
		$versions[1]
};

(:
    Get the name of the parent collection from a specified collection path.
:)
declare function browse:get-parent-collection($path as xs:string) as xs:string
{
    if($path eq "/db") then
        $path
    else
        replace($path, "/[^/]*$", "")
};

xquery version "1.0";
(: $Id$ :)
(:
    Module: display and browse collections.
:)

module namespace browse="http://exist-db.org/xquery/admin-interface/browse";

declare namespace request="http://exist-db.org/xquery/request";
declare namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace v="http://exist-db.org/versioning";

import module namespace date="http://exist-db.org/xquery/admin-interface/date" at "dates.xqm";

(:
    Main function: outputs the page.
:)
declare function browse:main() as element()
{
    let $colName := request:get-parameter("collection", "/db") return

            { browse:process-action($colName) }

Browsing Collection: {xdb:decode-uri(xs:anyURI($colName))}

            <form method="POST" enctype="multipart/form-data">
                {
                    browse:display-collection($colName)
                }

<input type="submit" name="action" value="Remove Selected"/>

                        <input type="submit" name="action" value="Create Collection"/>
                        New collection:

                        <input type="text" name="create" size="40"/>

                        <input type="submit" name="action" value="Upload"/>
                        <input type="file" size="30" name="upload"/>
                        Store as:

                        <input type="text" name="name" size="20"/>

                <input type="hidden" name="collection" value="{$colName}"/>
                <input type="hidden" name="panel" value="browse"/>
            </form>

};

(:
    Process an action.
:)
declare function browse:process-action($colName as xs:string) as element()*
{
    let $action := request:get-parameter("action", ()) return
        util:catch("java.lang.Exception",
            if($action eq "Remove Selected") then
            (
                browse:remove()
            )
            else if($action eq "Create Collection") then
            (
                browse:create-collection($colName)
            )
            else if($action eq "Store") then
            (
                browse:store($colName)
            )
            else if($action eq "Upload") then
            (
                browse:upload($colName)
            )else(),

                An error occurred while processing the action:

                {$util:exception-message}

        )
};

(:
    Store uploaded content.
:)
declare function browse:upload($colName as xs:string) as element()
{
    let $name := request:get-parameter("name", ()),
    $docName := if($name) then $name else request:get-uploaded-file-name("upload"),
    $file := request:get-uploaded-file("upload") return

Actions:

Storing uploaded content to: {$docName}

                {
                    xdb:decode-uri(xs:anyURI(xdb:store($colName, xdb:encode-uri($docName), $file)))
                }

};

(:
    Store files from an URI.

    Allowing this opens a security whole as a user can
    upload arbitrary files on the server if the process is running
    as root.
:)
declare function browse:store($colName as xs:string) as element()
{
    let $uri := request:get-parameter("uri", ()),
    $path := if(starts-with($uri, "file:")) then $uri else concat("file:", $uri),
    $docName := request:get-parameter("name", ()) return

Actions:

Storing resources from URI: {$path}

                {
                    xdb:store($colName, $docName, xs:anyURI($path))
                }

};

(:
    Remove a set of resources.
:)
declare function browse:remove() as element()
{
    let $resources := request:get-parameter("resource", ()) return

Actions:

                {
                    for $resource in $resources
                    return
                        browse:remove-resource($resource)
                }

};

(:
    Remove a resource.
:)
declare function browse:remove-resource($resource as xs:string) as element()*
{
    let $isBinary := util:binary-doc-available($resource),
    $doc := if ($isBinary) then $resource else doc($resource) return

        if($doc)then
        (

Removing document: {xdb:decode-uri(xs:anyURI($resource))} ...
,
            xdb:remove(util:collection-name($doc), util:document-name($doc))
        )
        else
        (

Removing collection: {xdb:decode-uri(xs:anyURI($resource))} ...
,
            xdb:remove($resource)
        )
};

(:
    Create a collection.
:)
declare function browse:create-collection($parentColName as xs:string) as element()
{
    let $newcol := request:get-parameter("create", ()) return

Actions:

            {
                if($newcol) then
                (
                    let $col := xdb:create-collection($parentColName, xdb:encode-uri($newcol)) return

Created collection: {xdb:decode-uri(xs:anyURI(util:collection-name($col)))}.

                )
                else
                (

No name specified for new collection!

                )
            }

};

(:
    Display the contents of a collection in a table view.
:)
declare function browse:display-collection($colName as xs:string) as element()
{

            Name
            Permissions
            Owner
            Group
            Created
            Modified
            Size (KB)
			Revision

            Up

        {
            browse:display-child-collections($colName),
            browse:display-child-resources($colName)
        }

};

declare function browse:display-child-collections($colName as xs:string) as element()*
{
    for $child in xdb:get-child-collections($colName)
        let $path := concat($colName, '/', $child),
        $created := xdb:created($path)
    order by $child return

            <input type="checkbox" name="resource" value="{$path}"/>
            {xdb:decode-uri(xs:anyURI($child))}
            {xdb:permissions-to-string(xdb:get-permissions($path))}
            {xdb:get-owner($path)}
            {xdb:get-group($path)}
            {date:format-dateTime($created)}

};

declare function browse:display-child-resources($colName as xs:string) as element()*
{
    for $child in xdb:get-child-resources($colName) order by $child
	return

            <input type="checkbox" name="resource" value="{$colName}/{$child}"/>
            {xdb:decode-uri(xs:anyURI($child))}
            {xdb:permissions-to-string(xdb:get-permissions($colName, $child))}
            {xdb:get-owner($colName, $child)}
            {xdb:get-group($colName, $child)}
            {date:format-dateTime(xdb:created($colName, $child))}
            {date:format-dateTime(xdb:last-modified($colName, $child))}
            {fn:ceiling(xdb:size($colName, $child) div 1024)}

				{browse:last-revision($colName, $child)//v:properties/v:revision/string()}

};

declare function browse:last-revision($collection as xs:string, $resource as xs:string) {
	let $vCollection := concat("/db/system/versions", $collection)
	let $versions :=
		for $version in collection($vCollection)/v:version[
			v:properties[v:document = $resource]
		]
		order by xs:long($version/v:properties/v:revision) descending
		return $version
	return
		$versions[1]
};

(:
    Get the name of the parent collection from a specified collection path.
:)
declare function browse:get-parent-collection($path as xs:string) as xs:string
{
    if($path eq "/db") then
        $path
    else
        replace($path, "/[^/]*$", "")
};


Update BaseX database module: add `db:alter-backup()` from version 9.3.

xquery version "3.1";
(:~
 : BaseX Database Module functions
 :
 : @see http://docs.basex.org/wiki/Database_Module
 :)
module namespace db = "http://basex.org/modules/db";

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

declare option o:requires "basex/7.0"; (: NOTE: 7.0 is the earliest version definitions are available for. :)

declare %a:since("basex", "7.0") function db:system() as element(system) external;
declare %a:since("basex", "9.0") function db:option($name as xs:string) as xs:string external;
declare %a:since("basex", "7.0") function db:info($db as xs:string) as element(database) external;
declare %a:since("basex", "8.6") function db:property($db as xs:string, $name as xs:string) as xs:anyAtomicType external;
declare %a:since("basex", "7.0") function db:list() as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string) as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string, $path as xs:string) as xs:string* external;
declare %a:since("basex", "7.1") function db:list-details() as element(database)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string) as element(resource)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string, $path as xs:string) as element(resource)* external;
declare %a:since("basex", "9.2") function db:dir($db as xs:string, $path as xs:string) as element()* external;
declare %a:since("basex", "7.0") function db:backups() as element(backup)* external;
declare %a:since("basex", "7.0") function db:backups($db as xs:string) as element(backup)* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string) as document-node()* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string, $path as xs:string) as document-node()* external;
declare %a:restrict-since("$pre", "basex", "9.3", "xs:integer*")
        %a:since("basex", "7.0") function db:open-pre($db as xs:string, $pre as xs:integer) as node()* external;
declare %a:restrict-since("$id", "basex", "9.3", "xs:integer*")
        %a:since("basex", "7.0") function db:open-id($db as xs:string, $id as xs:integer) as node()* external;
declare %a:since("basex", "7.0") function db:node-pre($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:node-id($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:text($db as xs:string, $strings as xs:string*) as text()* external;
declare %a:since("basex", "7.2.1") function db:text-range($db as xs:string, $min as xs:string, $max as xs:string) as text()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:string*) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:string*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.2.1") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string, $name as xs:string) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.5") function db:create($db as xs:string) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.5") function db:drop($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:add($db as xs:string, $input as item()) as empty-sequence() external;
declare %a:restrict-since("$path", "basex", "9.2", "xs:string?")
        %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:restrict-since("$path", "basex", "9.2", "xs:string?")
        %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:delete($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:copy($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:alter($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:create-backup($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:drop-backup($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "9.3") function db:alter-backup($name as xs:string, $new-name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:restore($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:rename($db as xs:string, $source as xs:string, $target as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item(), $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:store($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:since("basex", "7.3") function db:flush($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:name($node as node()) as xs:string external;
declare %a:since("basex", "7.7") function db:path($node as node()) as xs:string external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-raw($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-xml($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.1") function db:content-type($db as xs:string, $path as xs:string) as xs:string external;
declare %a:since("basex", "7.2.1") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:output") function db:output() external;
declare %a:since("basex", "8.2") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:cache") function db:output-cache() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string, $params as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "8.2") function db:event($name as xs:string, $query as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "7.8") function db:fulltext($db as item(), $terms as xs:string) as text()* external;

xquery version "3.1";
(:~
 : BaseX Database Module functions
 :
 : @see http://docs.basex.org/wiki/Database_Module
 :)
module namespace db = "http://basex.org/modules/db";

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

declare option o:requires "basex/7.0"; (: NOTE: 7.0 is the earliest version definitions are available for. :)

declare %a:since("basex", "7.0") function db:system() as element(system) external;
declare %a:since("basex", "9.0") function db:option($name as xs:string) as xs:string external;
declare %a:since("basex", "7.0") function db:info($db as xs:string) as element(database) external;
declare %a:since("basex", "8.6") function db:property($db as xs:string, $name as xs:string) as xs:anyAtomicType external;
declare %a:since("basex", "7.0") function db:list() as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string) as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string, $path as xs:string) as xs:string* external;
declare %a:since("basex", "7.1") function db:list-details() as element(database)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string) as element(resource)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string, $path as xs:string) as element(resource)* external;
declare %a:since("basex", "9.2") function db:dir($db as xs:string, $path as xs:string) as element()* external;
declare %a:since("basex", "7.0") function db:backups() as element(backup)* external;
declare %a:since("basex", "7.0") function db:backups($db as xs:string) as element(backup)* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string) as document-node()* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string, $path as xs:string) as document-node()* external;
declare %a:restrict-since("$pre", "basex", "9.3", "xs:integer*")
        %a:since("basex", "7.0") function db:open-pre($db as xs:string, $pre as xs:integer) as node()* external;
declare %a:restrict-since("$id", "basex", "9.3", "xs:integer*")
        %a:since("basex", "7.0") function db:open-id($db as xs:string, $id as xs:integer) as node()* external;
declare %a:since("basex", "7.0") function db:node-pre($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:node-id($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:text($db as xs:string, $strings as xs:string*) as text()* external;
declare %a:since("basex", "7.2.1") function db:text-range($db as xs:string, $min as xs:string, $max as xs:string) as text()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:string*) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:string*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.2.1") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string, $name as xs:string) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.5") function db:create($db as xs:string) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.5") function db:drop($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:add($db as xs:string, $input as item()) as empty-sequence() external;
declare %a:restrict-since("$path", "basex", "9.2", "xs:string?")
        %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:restrict-since("$path", "basex", "9.2", "xs:string?")
        %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:delete($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:copy($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:alter($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:create-backup($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:drop-backup($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:restore($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:rename($db as xs:string, $source as xs:string, $target as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item(), $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:store($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:since("basex", "7.3") function db:flush($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:name($node as node()) as xs:string external;
declare %a:since("basex", "7.7") function db:path($node as node()) as xs:string external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-raw($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-xml($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.1") function db:content-type($db as xs:string, $path as xs:string) as xs:string external;
declare %a:since("basex", "7.2.1") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:output") function db:output() external;
declare %a:since("basex", "8.2") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:cache") function db:output-cache() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string, $params as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "8.2") function db:event($name as xs:string, $query as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "7.8") function db:fulltext($db as item(), $terms as xs:string) as text()* external;


Clicking "Remove" activated/installed the app again. "Remove" still only removes the app from the list - it does not delete it from db.

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

xquery version "1.0";

module namespace repomanager="http://exist-db.org/xquery/admin-interface/repo";

declare namespace package="http://expath.org/ns/pkg";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace util="http://exist-db.org/xquery/util";

declare variable $repomanager:coll := "/db/system/repo";
declare variable $repomanager:repo-uri := if (request:get-parameter("repository-url", ())) then
              request:get-parameter("repository-url", ())
            else
              "http://demo.exist-db.org/exist/repo/public/all/";

declare function local:entry-data($path as xs:anyURI, $type as xs:string, $data as item()?, $param as item()*) as item()?
{

	<entry>
		<path>{$path}</path>
		<type>{$type}</type>
		<data>{$data}</data>
	</entry>
};

declare function local:entry-filter($path as xs:anyURI, $type as xs:string, $param as item()*) as xs:boolean
{
	$path = ("repo.xml", "expath-pkg.xml")
};

declare function repomanager:publicrepo() as element()
{
let $package-url := request:get-parameter("package-url", ())
return

Actions:

                {
                if (ends-with($package-url,'.xar')) then
                    (
uploaded package: {$package-url}
,

                    let $http-response := httpclient:get(xs:anyURI($package-url), false(), ())
                    let $name := tokenize($package-url, "/")[last()]
                    return
                    let $package-mimetype := "application/xar",
                    $package-data := xs:base64Binary($http-response/httpclient:body/text())
                    return
                    xmldb:store($repomanager:coll, $name, $package-data, $package-mimetype)
                    )
                else

Error uploading - Must be a valid Package archive (.xar file extension)

                }

                Important: installed XQuery library mappings will not become visible until eXist is restarted.

};

declare function repomanager:upload() as element()
{
    let $name := request:get-parameter("name", ()),
    $repocol :=  if (collection($repomanager:coll)) then () else xmldb:create-collection('/db/system','repo'),
    $docName := if($name) then $name else request:get-uploaded-file-name("upload"),
    $file := request:get-uploaded-file-data("upload") return

Actions:

                {
                if ($docName) then
                    (
uploaded package: {$docName}
,

                    xdb:decode-uri(xs:anyURI(xdb:store($repomanager:coll, xdb:encode-uri($docName), $file)))
                    )
                else

Error uploading - Must be a valid Package archive (.xar file extension)

                }

};

declare function repomanager:activate() as element()
{
    let $name := request:get-parameter("name", ())
    let $package := request:get-parameter("package", ())
    let $type := request:get-parameter("type", ())
    let $hostname := request:get-hostname()            (:  pkg-repo.jar needs http or file scheme :)
    let $port := request:get-server-port()
     return

Actions:

Installed package: {$name}

                {
                    repo:install(concat('http://localhost:',$port,'/exist/rest',$repomanager:coll,'/',$name,'.xar')),
                    if ($type eq "application") then
                        repo:deploy($package)
                    else
                        ()
                }

};

declare function repomanager:deactivate() as element()
{
    let $name := request:get-parameter("name", ())
    let $package := request:get-parameter("package", ())
    let $type := request:get-parameter("type", ())
     return

Actions:

Uninstalled package: {$name}

                {
                    if ($type eq "application") then
                        repo:undeploy($package)
                    else
                        (),
                    repo:remove($package)
                }

                Important: Installed XQuery libraries written in Java only become visible after a restart of eXist-db.

};

declare function repomanager:remove() as element()
{
    let $name := request:get-parameter("name", ())
     return

Actions:

removed package: {$name}

                {xmldb:remove($repomanager:coll,concat($name,'.xar'))}

};

declare function repomanager:process-action() as element()*
{
    let $action := request:get-parameter("action", ()) return
        util:catch("java.lang.Exception",
            if($action eq "remove") then
            (
                repomanager:remove()
            )
            else if($action eq "activate") then
            (
                repomanager:activate()
            )
            else if($action eq "deactivate") then
            (
                repomanager:deactivate()
            )
            else if($action eq "Upload Package") then
            (
                repomanager:upload()
            )
            else if($action eq "Download from Public Repository") then
            (
                repomanager:publicrepo()
            )else(),

                An error occurred while processing the action:

                {$util:exception-message}

        )
};

declare function repomanager:main() as element() {
    let $action := lower-case(request:get-parameter("action", "set repository"))
    let $repocol :=  if (collection($repomanager:coll)) then () else xmldb:create-collection('/db/system','repo')

    return

Package Repository

        <form action="?panel=repo" method="POST" enctype="multipart/form-data">
        { repomanager:process-action() }
        {
         let $files := if (collection($repomanager:coll)) then collection($repomanager:coll)/util:document-name(.)[contains(.,'.xar')] else ()
         return
            if (exists($files)) then

                        Name
                        Description
                        Date Installed
                        Status
                        Action

                    {
                        let $repos := repo:list()
                       for $file in $files
                       let $package-name := substring-before($file,'.xar')
                       let $xar := util:binary-doc(concat($repomanager:coll,'/',$file))

                       let $meta := compression:unzip($xar, util:function(xs:QName("local:entry-filter"), 3), (),  util:function(xs:QName("local:entry-data"), 4), ())
                       let $package := $meta//package:package
                       let $pkg-name := $package/string(@name)
                       let $pkg-abbrev := $package/string(@abbrev)
                       let $repo := $meta//repo:meta
                       let $type := $repo//repo:type/string()

                       let $installed := exists($repos[. eq $pkg-name])
                       return

                           {$pkg-name}

                           {$type}
                           { ( $repo//repo:description, $package/string(package:title) )[1]}

                           {xmldb:last-modified($repomanager:coll, concat($package-name,'.xar'))}

                           {if ($installed) then
                               Installed
                           else
                               Not Installed
                           }

                           {
                            if($installed) then
                                Uninstall
                            else (
                                Install,
                                 | ,
                                Remove
                            )
                           }

                   }

            else
                ()
        }
                Important: Installed XQuery libraries written in Java only become visible after a restart of eXist-db.

                        <input type="submit" name="action" value="Download from Public Repository"/>

                        <select size="5" width="200" style="width:340px" name="package-url">
                           {
                            let $packages := httpclient:get(xs:anyURI($repomanager:repo-uri),false(),())//httpclient:body/node()
                             return
                             for $package in $packages//package[contains(url/.,'.xar')]
                             return
                                <option value="{$package/url}">{tokenize($package/url, "/")[last()]}</option>
                           }
                        </select>

                         Public Repository URL :

                        <input name="repository-url" size="40" value="{$repomanager:repo-uri}"/>
                        <input type="submit" name="action" value="set repository"/>

                        <input type="submit" name="action" value="Upload Package"/>
                        <input type="file" size="30" name="upload"/>

                Note: You can upload example .xar packages located under webapp/repo/packages
          </form>

};


Added array(*) test

Added array(*) test

xquery version "3.0";

(:~
 : Tests textual representation of datatypes
 :)
module namespace tps="http://exist-db.org/test/types";

import module namespace inspect="http://exist-db.org/xquery/inspection" at "java:org.exist.xquery.functions.inspect.InspectionModule";

declare namespace test="http://exist-db.org/xquery/xqsuite";

declare
    %test:assertEquals("map(*)")
function tps:map_type() {
    data(inspect:inspect-function(map:entry#2)//returns/@type)
};

declare
    %test:assertEquals("empty-sequence()")
function tps:empty_sequence() {
    data(inspect:inspect-function(fn:error#2)//returns/@type)
};

declare
    %test:assertEquals("document-node()")
function tps:document_node() {
    data(inspect:inspect-function(fn:doc#1)//returns/@type)
};

declare
    %test:assertEquals("xs:string")
function tps:string() {
    data(inspect:inspect-function(fn:format-date#2)//returns/@type)
};

declare
    %test:assertEquals("xs:integer")
function tps:integer() {
    data(inspect:inspect-function(fn:function-arity#1)//returns/@type)
};

declare
    %test:assertEquals("function(*)")
function tps:function() {
    data(inspect:inspect-function(fn:function-lookup#2)//returns/@type)
};

declare
    %test:assertEquals("xs:QName")
function tps:xqname() {
    data(inspect:inspect-function(fn:function-name#1)//returns/@type)
};

declare
    %test:assertEquals("array(*)")
function tps:array() {
    data(inspect:inspect-function(array:append#2)//returns/@type)
};


fixing some mcsd conformance issues

fixing some mcsd conformance issues

module namespace page = 'http://basex.org/modules/web-page';
import module namespace csd_bl = "https://github.com/openhie/openinfoman/csd_bl";
import module namespace functx = 'http://www.functx.com';
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace svs_lsvs = "https://github.com/openhie/openinfoman/svs_lsvs";
declare namespace csd =  "urn:ihe:iti:csd:2013";
declare namespace svs = "urn:ihe:iti:svs:2008";
declare namespace UUID = "java.util.UUID";
declare default element  namespace   "urn:ihe:iti:csd:2013";
declare variable $page:namespace_uuid := "10df44d2-55f4-11e4-af21-705681a860b7";

declare function page:uuid_tobits($tokens) {
  if (count($tokens) > 1)
  then  (
          bin:hex(concat($tokens[1],$tokens[2])),
          page:uuid_tobits(subsequence($tokens,3))
        )
  else $tokens
};

declare function page:getDayOfTheWeek ($day) {
  if($day = 1) then "mon"
  else if ($day = 2) then "tue"
  else if ($day = 3) then "wed"
  else if ($day = 4) then "thu"
  else if ($day = 5) then "fri"
  else if ($day = 6) then "sat"
  else if ($day = 7) then "sun"
  else ()
};

declare function page:uuid_generate($name,$namespace) {
  let $ns_bits := page:uuid_tobits(functx:chars(translate($namespace,'-','' )))
  let $n_bytes := convert:string-to-base64($name)
  let $uuid := UUID:nameUUIDFromBytes(  bin:join(($ns_bits, $n_bytes)))
  return lower-case($uuid)
};

declare function page:get_location ($doc_name,$_id,$page,$_count,$_since)
{
  <CSD xmlns:csd="urn:ihe:iti:csd:2013">
    {
      let $search_collection :=
      <collection>
        <search directory="facilityDirectory">urn:ihe:iti:csd:2014:stored-function:facility-search</search>
        <search directory="organizationDirectory">urn:ihe:iti:csd:2014:stored-function:organization-search</search>
      </collection>
      for $search in $search_collection/search
      let $search_name := $search/text()
      return
      (
        let $careServicesSubRequest :=
        <csd:careServicesRequest>
          <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL('')}">
            <csd:requestParams>
              {
                let $id := $_id
                return if (functx:all-whitespace($id)) then () else <csd:id entityID="{$id}"/>
              }

              {
                let $t_start := $page
                return if (functx:is-a-number($t_start))
                  then
                    let $start := max((xs:int($t_start),1))
                    let $t_count := $_count
                    let $count := if(functx:is-a-number($t_count)) then  max((xs:int($t_count),1)) else 50
                    let $startIndex := ($start - 1)*$count + 1
                    return <csd:start>{$startIndex}</csd:start>
                  else ()
              }
         {
           let $count := $_count
           return
              if(functx:is-a-number($count))
              then  <csd:max>{max((xs:int($count),1))} </csd:max>
              else ()
         }
         {
          let $since := $_since
          return if (functx:all-whitespace($since)) then () else <csd:record updated="{$since}"/>
         }
            </csd:requestParams>
          </csd:function>
        </csd:careServicesRequest>

        let $doc :=  csd_dm:open_document($doc_name)
        let $contents := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
        let $directory := $search/@directory/string()
        return $contents/*[name() = $directory]
      )
    }
  </CSD>
};

declare
  %rest:path("/mcsd")
  %rest:GET
  function page:FHIR()
{
  let $output :=
                <json type='object'>
                  <issue type="array">
                    <_ type="object">
                      processing
                      <diagnostics>This is the base URL of FHIR server. Unable to handle this request, as it does not contain a resource type or operation name. to get Locations use http://localhost:8984/doc_name/mcsd/Location</diagnostics>

                        <text>Internal server error</text>

                      <severity>error</severity>
                    </_>
                  </issue>
                  <resourceType>OperationOutcome</resourceType>
                </json>
    return (
              <rest:response>
                <output:serialization-parameters>
                  <output:media-type value='application/json'/>
                </output:serialization-parameters>
              </rest:response>,
              json:serialize($output,map{"format":"direct",'escape': 'no'})
            )
};

declare
  %rest:path("/{$doc_name}/mcsd/Location")
  %rest:query-param("_id", "{$_id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:GET
  function page:FHIRLocation($_id,$page,$_count,$_since,$doc_name)
{
let $contents := page:get_location ($doc_name,$_id,$page,$_count,$_since)
let $location :=
<json type='object'>
<resourceType>Bundle</resourceType>
<type>batch</type>
<meta type="object">
  <lastUpdated>{current-dateTime()}</lastUpdated>
</meta>
<timestamp>{current-dateTime()}</timestamp>
<id>{random:uuid()}</id>
<entry type="array">
{
for $content in ($contents/facilityDirectory/facility,$contents/organizationDirectory/organization)
let $entityType := $content/name()
let $orgUUID := page:uuid_generate($content/@entityID, $page:namespace_uuid)
let $organizationResource :=
  if($entityType = "csd:facility" or $entityType = "facility") then
    (
      <_ type="object">
      <request type="object">
        <method>PUT</method>
        <url>Organization/{$orgUUID}</url>
      </request>
      <resource type="object">
        <resourceType>Organization</resourceType>
        <meta type="object">
          <profile type="array">
            <_>http://ihe.net/fhir/StructureDefinition/IHE_mCSD_Organization</_>
            <_>http://ihe.net/fhir/StructureDefinition/IHE_mCSD_FacilityOrganization</_>
          </profile>
        </meta>
        <name>{$content/primaryName/text()}</name>
        <id>{$orgUUID}</id>
        <type type="array">
          <_ type="object">
            <coding type="array">
              <_ type="object">
                <system>urn:ietf:rfc:3986</system>
                urn:ihe:iti:mcsd:2019:facility
                <display>Facility</display>
                <userSelected>false</userSelected>
              </_>
            </coding>
          </_>
        </type>
      </resource>
      </_>
    )
  else ()
  let $locationResource :=
<_ type="object">
  <fullURL>{csd_webui:generateURL($doc_name || "/mcsd/Location/" || replace($content/@entityID/string(), "urn:uuid:", ""))}</fullURL>
  <request type="object">
    <method>PUT</method>
    <url>Location/{replace($content/@entityID/string(), "urn:uuid:", "")}</url>
  </request>
  <resource type="object">
    <resourceType>Location</resourceType>
      <meta type="object">
        <lastUpdated>{$content/record/@updated/string()}</lastUpdated>
        {
          if($entityType = "csd:facility" or $entityType = "facility") then
          (
            <profile type="array">
              <_>http://ihe.net/fhir/StructureDefinition/IHE_mCSD_Location</_>
              <_>http://ihe.net/fhir/StructureDefinition/IHE_mCSD_FacilityLocation</_>
            </profile>
          )
          else if($entityType = "csd:organization" or $entityType = "organization") then
          (
            <profile type="array">
              <_>http://ihe.net/fhir/StructureDefinition/IHE_mCSD_Location</_>
            </profile>
          )
          else()
        }
        <tag type="array">
        <_ type="object">
            {$content/record/@sourceDirectory/string()}
            <system>https://github.com/openhie/openinfoman/tags/fhir/sourceDirectory</system>
          </_>
        </tag>
      </meta>
    <id>{replace($content/@entityID/string(), "urn:uuid:", "")}</id>
    {
     if(exists($content/otherID))
     then
     <identifier type="array">
      {
      for $otherid in $content/otherID
      return
      <_ type="object">
        <value>{$otherid/text()}</value>
        {
          if($otherid/@code/string()) then
          (
            <type type="object">
              <text>{$otherid/@code/string()}</text>
            </type>
          )
          else ()
        }
        <assigner type="object">
          <display>{$otherid/@assigningAuthorityName/string()}</display>
        </assigner>
      </_>
      }
      <_ type="object">
        <system>urn:ihe:iti:csd:2013:entityID</system>
        <value>{replace($content/@entityID/string(), "urn:uuid:", "")}</value>
        <type type="object">
          <text>entityID</text>
        </type>
      </_>
     </identifier>
     else ()
    }
    {
      let $search_name := "urn:ihe:iti:csd:2014:stored-function:organization-search"
      let $parent :=
      if(exists($content/organizations/organization))
      then
      $content/organizations/organization/@entityID/string()
      else
      if (exists($content/parent))
      then $content/parent/@entityID/string()
      else ()

      return if($parent)
      then
      let $careServicesSubRequest :=
      <csd:careServicesRequest>
        <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
          <csd:requestParams>
            <csd:id entityID="{$parent}"/>
          </csd:requestParams>
        </csd:function>
      </csd:careServicesRequest>
      let $doc :=  csd_dm:open_document($doc_name)
      let $organization := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
      return if(exists($organization/organizationDirectory/organization))
      then
      <partOf type="object">
        <reference>{"Location/" || replace($organization/organizationDirectory/organization/@entityID/string(), "urn:uuid:", "")}</reference>
        <display>{$organization/organizationDirectory/organization/primaryName/text()}</display>
      </partOf>
      else ()
      else ()
    }
    <physicalType type="object">
      <coding type="array">
        <_ type="object">
          <system>http://hl7.org/fhir/location-physical-type</system>
          {
            if($entityType = "csd:facility" or $entityType = "facility") then
            ( bu,
              <display>Building</display>
            )
            else if($entityType = "csd:organization" or $entityType = "organization") then
            (
              jdn,
              <display>Jurisdiction</display>
            )
            else ()
          }
        </_>
      </coding>
      {
        if($entityType = "csd:facility" or $entityType = "facility") then
          <text>Building</text>
        else if($entityType = "csd:organization" or $entityType = "organization") then
          <text>Jurisdiction</text>
        else ()
      }
    </physicalType>
    {
      if($entityType = "csd:facility" or $entityType = "facility") then
        <managingOrganization type="object">
          <reference>Organization/{$orgUUID}</reference>
        </managingOrganization>
      else ()
    }
    {
    if(exists($content/contactPoint))
    then
    <telecom type="array">
     {
      for $contactPoint in $content/contactPoint
      return
        <_ type="object">
        {
          <system>
            {
              let $code := $contactPoint/codedType/@code/string()
              return if($code = "BP") then "phone"
                else if ($code = "EMAIL") then "email"
                else if ($code = "FAX") then "fax"
                else "other"
            }
          </system>
        }
          <value>{$contactPoint/codedType/text()}</value>
        </_>
     }
    </telecom>
    else ()
    }
    {
    if(exists($content/address/addressLine))
        then
        <address type="array">
          {
            for $address in $content/address
            return
              if(exists($address/addressLine))
              then
              <_ type="object">
                {
                  let $csdtype := lower-case($address/@type/string())
                  let $fhirtype := if($csdtype = "mailing" or $csdtype = "mailing address") then "postal"
                                    else if ($csdtype = "physical" or $csdtype = "physical address") then "physical"
                                    else ()
                  return if($fhirtype)
                          then <type>{$fhirtype}</type>
                          else ()
                }
                {
                  for $addressLine in $address/addressLine
                  return if($addressLine/@component = "streetAddress")
                    then <line>{$addressLine/text()}</line>
                    else if($addressLine/@component = "city")
                    then <city>{$addressLine/text()}</city>
                    else if($addressLine/@component = "district")
                    then <district>{$addressLine/text()}</district>
                    else if($addressLine/@component = "stateProvince")
                    then <state>{$addressLine/text()}</state>
                    else if($addressLine/@component = "country")
                    then <country>{$addressLine/text()}</country>
                    else if($addressLine/@component = "postalCode")
                    then <postalCode>{$addressLine/text()}</postalCode>
                    else()
                }
              </_>
              else ()
          }
        </address>
        else ()
    }
    {
      if(exists($content/geocode))
      then
      <position type="object">
        <longitude>{$content/geocode/longitude/text()}</longitude>
        <latitude>{$content/geocode/latitude/text()}</latitude>
        {
          if($content/geocode/altitude/text()) then
            <altitude>{$content/geocode/altitude/text()}</altitude>
          else ()
        }
      </position>
      else ()
    }
    <type type="array">
      {
        if($entityType = "csd:facility" or $entityType = "facility") then
          <_ type="object">
            <coding type="array">
              <_ type="object">
                <system>urn:ietf:rfc:3986</system>
                urn:ihe:iti:mcsd:2019:facility
                <display>Facility</display>
                <userSelected>false</userSelected>
              </_>
            </coding>
          </_>
        else ()
      }
      {
        for $codedType in $content/codedType
          return
            <_ type="object">
              <coding type="array">
                <_ type="object">
                  {$codedType/@code/string()}
                  <system>{$codedType/@codingScheme/string()}</system>
                  {
                  if(functx:all-whitespace($codedType/text()))
                  then ()
                  else
                  <display>{$codedType/text()}</display>
                  }
                </_>
              </coding>
              <text>{$codedType/text()}</text>
            </_>
      }
    </type>
    <status>{lower-case($content/record/@status/string())}</status>
    <name>{$content/primaryName/text()}</name>
    {
      if($content/otherName) then
        <alias type="array">
        {
          for $otherName in $content/otherName
            return
              <_>{$otherName/string()}</_>
        }
        </alias>
      else ()
    }
    {
      if(exists($content/operatingHours))then
      <hoursOfOperation type="array">
      {
        for $operatingHours in $content/operatingHours
          return
          <_ type="object">
          {
            let $CSDdayOfTheWeek := $operatingHours/dayOfTheWeek/text()
              let $FHIRdayOfTheWeek := page:getDayOfTheWeek($CSDdayOfTheWeek)
              return (
                <daysOfWeek>{$FHIRdayOfTheWeek}</daysOfWeek>,
                <openingTime>{$operatingHours/beginningHour/text()}</openingTime>,
                <closingTime>{$operatingHours/endingHour/text()}</closingTime>
              )
          }
          </_>
      }
      </hoursOfOperation>
      else ()
    }
  </resource>
</_>
  return($organizationResource,$locationResource)
}
</entry>
</json>
return (
  <rest:response>
    <output:serialization-parameters>
      <output:media-type value='application/json'/>
    </output:serialization-parameters>
  </rest:response>,
  json:serialize($location,map{"format":"direct",'escape': 'no'})
  )

};

module namespace page = 'http://basex.org/modules/web-page';
import module namespace csd_bl = "https://github.com/openhie/openinfoman/csd_bl";
import module namespace functx = 'http://www.functx.com';
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace svs_lsvs = "https://github.com/openhie/openinfoman/svs_lsvs";
declare namespace csd =  "urn:ihe:iti:csd:2013";
declare namespace svs = "urn:ihe:iti:svs:2008";
declare namespace UUID = "java.util.UUID";
declare default element  namespace   "urn:ihe:iti:csd:2013";
declare variable $page:namespace_uuid := "10df44d2-55f4-11e4-af21-705681a860b7";

declare function page:uuid_tobits($tokens) {
  if (count($tokens) > 1)
  then  (
          bin:hex(concat($tokens[1],$tokens[2])),
          page:uuid_tobits(subsequence($tokens,3))
        )
  else $tokens
};

declare function page:getDayOfTheWeek ($day) {
  if($day = 1) then "mon"
  else if ($day = 2) then "tue"
  else if ($day = 3) then "wed"
  else if ($day = 4) then "thu"
  else if ($day = 5) then "fri"
  else if ($day = 6) then "sat"
  else if ($day = 7) then "sun"
  else ()
};

declare function page:uuid_generate($name,$namespace) {
  let $ns_bits := page:uuid_tobits(functx:chars(translate($namespace,'-','' )))
  let $n_bytes := convert:string-to-base64($name)
  let $uuid := UUID:nameUUIDFromBytes(  bin:join(($ns_bits, $n_bytes)))
  return lower-case($uuid)
};

declare function page:get_location ($doc_name,$_id,$page,$_count,$_since)
{
  <CSD xmlns:csd="urn:ihe:iti:csd:2013">
    {
      let $search_collection :=
      <collection>
        <search directory="facilityDirectory">urn:ihe:iti:csd:2014:stored-function:facility-search</search>
        <search directory="organizationDirectory">urn:ihe:iti:csd:2014:stored-function:organization-search</search>
      </collection>
      for $search in $search_collection/search
      let $search_name := $search/text()
      return
      (
        let $careServicesSubRequest :=
        <csd:careServicesRequest>
          <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL('')}">
            <csd:requestParams>
              {
                let $id := $_id
                return if (functx:all-whitespace($id)) then () else <csd:id entityID="{$id}"/>
              }

              {
                let $t_start := $page
                return if (functx:is-a-number($t_start))
                  then
                    let $start := max((xs:int($t_start),1))
                    let $t_count := $_count
                    let $count := if(functx:is-a-number($t_count)) then  max((xs:int($t_count),1)) else 50
                    let $startIndex := ($start - 1)*$count + 1
                    return <csd:start>{$startIndex}</csd:start>
                  else ()
              }
         {
           let $count := $_count
           return
              if(functx:is-a-number($count))
              then  <csd:max>{max((xs:int($count),1))} </csd:max>
              else ()
         }
         {
          let $since := $_since
          return if (functx:all-whitespace($since)) then () else <csd:record updated="{$since}"/>
         }
            </csd:requestParams>
          </csd:function>
        </csd:careServicesRequest>

        let $doc :=  csd_dm:open_document($doc_name)
        let $contents := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
        let $directory := $search/@directory/string()
        return $contents/*[name() = $directory]
      )
    }
  </CSD>
};

declare
  %rest:path("/mcsd")
  %rest:GET
  function page:FHIR()
{
  let $output :=
                <json type='object'>
                  <issue type="array">
                    <_ type="object">
                      processing
                      <diagnostics>This is the base URL of FHIR server. Unable to handle this request, as it does not contain a resource type or operation name. to get Locations use http://localhost:8984/doc_name/mcsd/Location</diagnostics>

                        <text>Internal server error</text>

                      <severity>error</severity>
                    </_>
                  </issue>
                  <resourceType>OperationOutcome</resourceType>
                </json>
    return (
              <rest:response>
                <output:serialization-parameters>
                  <output:media-type value='application/json'/>
                </output:serialization-parameters>
              </rest:response>,
              json:serialize($output,map{"format":"direct",'escape': 'no'})
            )
};

declare
  %rest:path("/{$doc_name}/mcsd/Location")
  %rest:query-param("_id", "{$_id}")
  %rest:query-param("page", "{$page}")
  %rest:query-param("_count", "{$_count}")
  %rest:query-param("_since", "{$_since}")
  %rest:GET
  function page:FHIRLocation($_id,$page,$_count,$_since,$doc_name)
{
let $contents := page:get_location ($doc_name,$_id,$page,$_count,$_since)
let $location :=
<json type='object'>
<resourceType>Bundle</resourceType>
<total>{count($contents/facilityDirectory/facility) + count($contents/organizationDirectory/organization)}</total>
<type>batch</type>
<meta type="object">
  <lastUpdated>{current-dateTime()}</lastUpdated>
</meta>
<timestamp>{current-dateTime()}</timestamp>
<id>{concat('urn:uuid:', random:uuid())}</id>
<entry type="array">
{
for $content in ($contents/facilityDirectory/facility,$contents/organizationDirectory/organization)
let $entityType := $content/name()
let $orgUUID := concat('urn:uuid:', page:uuid_generate($content/@entityID, $page:namespace_uuid))
let $organizationResource :=
  if($entityType = "csd:facility" or $entityType = "facility") then
    (
      <_ type="object">
      <fullURL>{csd_webui:generateURL($doc_name || "/mcsd/Organization/" || $orgUUID)}</fullURL>
      <request type="object">
        <method>PUT</method>
        <url>Organization/{$orgUUID}</url>
      </request>
      <resource type="object">
        <resourceType>Organization</resourceType>
        <meta type="object">
          <profile>mCSDFacility</profile>
        </meta>
        <name>{$content/primaryName/text()}</name>
        <id>{$orgUUID}</id>
        <type type="array">
          <_ type="object">
            <coding type="array">
              <_ type="object">
                <system>urn:ietf:rfc:3986</system>
                urn:ihe:iti:mcsd:2019:facility
                <display>Facility</display>
                <userSelected>false</userSelected>
              </_>
            </coding>
          </_>
        </type>
      </resource>
      </_>
    )
  else ()
  let $locationResource :=
<_ type="object">
  <fullURL>{csd_webui:generateURL($doc_name || "/mcsd/Location/" || $content/@entityID)}</fullURL>
  <request type="object">
    <method>PUT</method>
    <url>Location/{$content/@entityID/string()}</url>
  </request>
  <resource type="object">
    <resourceType>Location</resourceType>
      <meta type="object">
        <lastUpdated>{$content/record/@updated/string()}</lastUpdated>
        {
          if($entityType = "csd:facility" or $entityType = "facility") then
          (<profile>mCSDFacility</profile>)
          else if($entityType = "csd:organization" or $entityType = "organization") then
          (<profile>mCSD</profile>)
          else()
        }
        <tag type="array">
        <_ type="object">
            {$content/record/@sourceDirectory/string()}
            <system>https://github.com/openhie/openinfoman/tags/fhir/sourceDirectory</system>
          </_>
        </tag>
      </meta>
    <id>{$content/@entityID/string()}</id>
    {
     if(exists($content/otherID))
     then
     <identifier type="array">
      {
      for $otherid in $content/otherID
      return
      <_ type="object">
        <value>{$otherid/text()}</value>
        {
          if($otherid/@code/string()) then
          (
            <type type="object">
              <text>{$otherid/@code/string()}</text>
            </type>
          )
          else ()
        }
        <assigner type="object">
          <display>{$otherid/@assigningAuthorityName/string()}</display>
        </assigner>
      </_>
      }
      <_ type="object">
        <system>urn:ihe:iti:csd:2013:entityID</system>
        <value>{$content/@entityID/string()}</value>
        <type type="object">
          <text>entityID</text>
        </type>
      </_>
     </identifier>
     else ()
    }
    {
      let $search_name := "urn:ihe:iti:csd:2014:stored-function:organization-search"
      let $parent :=
      if(exists($content/organizations/organization))
      then
      $content/organizations/organization/@entityID/string()
      else
      if (exists($content/parent))
      then $content/parent/@entityID/string()
      else ()

      return if($parent)
      then
      let $careServicesSubRequest :=
      <csd:careServicesRequest>
        <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
          <csd:requestParams>
            <csd:id entityID="{$parent}"/>
          </csd:requestParams>
        </csd:function>
      </csd:careServicesRequest>
      let $doc :=  csd_dm:open_document($doc_name)
      let $organization := csr_proc:process_CSR_stored_results( $doc , $careServicesSubRequest)
      return if(exists($organization/organizationDirectory/organization))
      then
      <partOf type="object">
        <reference>{csd_webui:generateURL($doc_name || "/mcsd/Location/" || $organization/organizationDirectory/organization/@entityID/string())}</reference>
        <display>{$organization/organizationDirectory/organization/primaryName/text()}</display>
      </partOf>
      else ()
      else ()
    }
    <physicalType type="object">
      <coding type="array">
        <_ type="object">
          <system>http://hl7.org/fhir/location-physical-type</system>
          {
            if($entityType = "csd:facility" or $entityType = "facility") then
            ( bu,
              <display>Building</display>
            )
            else if($entityType = "csd:organization" or $entityType = "organization") then
            (
              jdn,
              <display>Jurisdiction</display>
            )
            else ()
          }
        </_>
      </coding>
      {
        if($entityType = "csd:facility" or $entityType = "facility") then
          <text>Building</text>
        else if($entityType = "csd:organization" or $entityType = "organization") then
          <text>Jurisdiction</text>
        else ()
      }
    </physicalType>
    {
      if($entityType = "csd:facility" or $entityType = "facility") then
        <managingOrganization type="object">
          <reference>Organization/{$orgUUID}</reference>
        </managingOrganization>
      else ()
    }
    {
    if(exists($content/contactPoint))
    then
    <telecom type="array">
     {
      for $contactPoint in $content/contactPoint
      return
        <_ type="object">
        {
          <system>
            {
              let $code := $contactPoint/codedType/@code/string()
              return if($code = "BP") then "phone"
                else if ($code = "EMAIL") then "email"
                else if ($code = "FAX") then "fax"
                else "other"
            }
          </system>
        }
          <value>{$contactPoint/codedType/text()}</value>
        </_>
     }
    </telecom>
    else ()
    }
    {
    if(exists($content/address/addressLine))
        then
        <address type="array">
          {
            for $address in $content/address
            return
              if(exists($address/addressLine))
              then
              <_ type="object">
                {
                  let $csdtype := lower-case($address/@type/string())
                  let $fhirtype := if($csdtype = "mailing" or $csdtype = "mailing address") then "postal"
                                    else if ($csdtype = "physical" or $csdtype = "physical address") then "physical"
                                    else ()
                  return if($fhirtype)
                          then <type>{$fhirtype}</type>
                          else ()
                }
                {
                  for $addressLine in $address/addressLine
                  return if($addressLine/@component = "streetAddress")
                    then <line>{$addressLine/text()}</line>
                    else if($addressLine/@component = "city")
                    then <city>{$addressLine/text()}</city>
                    else if($addressLine/@component = "district")
                    then <district>{$addressLine/text()}</district>
                    else if($addressLine/@component = "stateProvince")
                    then <state>{$addressLine/text()}</state>
                    else if($addressLine/@component = "country")
                    then <country>{$addressLine/text()}</country>
                    else if($addressLine/@component = "postalCode")
                    then <postalCode>{$addressLine/text()}</postalCode>
                    else()
                }
              </_>
              else ()
          }
        </address>
        else ()
    }
    {
      if(exists($content/geocode))
      then
      <position type="object">
        <longitude>{$content/geocode/longitude/text()}</longitude>
        <latitude>{$content/geocode/latitude/text()}</latitude>
        {
          if($content/geocode/altitude/text()) then
            <altitude>{$content/geocode/altitude/text()}</altitude>
          else ()
        }
      </position>
      else ()
    }
    <type type="array">
      {
        if($entityType = "csd:facility" or $entityType = "facility") then
          <_ type="object">
            <coding type="array">
              <_ type="object">
                <system>urn:ietf:rfc:3986</system>
                urn:ihe:iti:mcsd:2019:facility
                <display>Facility</display>
                <userSelected>false</userSelected>
              </_>
            </coding>
          </_>
        else ()
      }
      {
        for $codedType in $content/codedType
          return
            <_ type="object">
              <coding type="array">
                <_ type="object">
                  {$codedType/@code/string()}
                  <system>{$codedType/@codingScheme/string()}</system>
                  {
                  if(functx:all-whitespace($codedType/text()))
                  then ()
                  else
                  <display>{$codedType/text()}</display>
                  }
                </_>
              </coding>
              <text>{$codedType/text()}</text>
            </_>
      }
    </type>
    <status>{$content/record/@status/string()}</status>
    <name>{$content/primaryName/text()}</name>
    {
      if($content/otherName) then
        <alias type="array">
        {
          for $otherName in $content/otherName
            return
              <_>{$otherName/string()}</_>
        }
        </alias>
      else ()
    }
    {
      if(exists($content/operatingHours))then
      <hoursOfOperation type="array">
      {
        for $operatingHours in $content/operatingHours
          return
          <_ type="object">
          {
            let $CSDdayOfTheWeek := $operatingHours/dayOfTheWeek/text()
              let $FHIRdayOfTheWeek := page:getDayOfTheWeek($CSDdayOfTheWeek)
              return (
                <daysOfWeek>{$FHIRdayOfTheWeek}</daysOfWeek>,
                <openingTime>{$operatingHours/beginningHour/text()}</openingTime>,
                <closingTime>{$operatingHours/endingHour/text()}</closingTime>
              )
          }
          </_>
      }
      </hoursOfOperation>
      else ()
    }
  </resource>
</_>
  return($organizationResource,$locationResource)
}
</entry>
</json>
return (
  <rest:response>
    <output:serialization-parameters>
      <output:media-type value='application/json'/>
    </output:serialization-parameters>
  </rest:response>,
  json:serialize($location,map{"format":"direct",'escape': 'no'})
  )

};