[ignore] removed "download" button from backup form. click on the link instead.

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

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

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

declare variable $backup:BACKUP_DIR := "export";

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

Backups

            {
                if ($action eq "trigger") then
                    backup:trigger()
                else
                    ()
            }
            { backup:display() }

};

declare function backup:get-directory() {
    let $home := system:get-exist-home()
    return
        if (ends-with($home, "WEB-INF")) then
            concat($home, "/data/", $backup:BACKUP_DIR)
        else
            concat($home, "/webapp/WEB-INF/data/", $backup:BACKUP_DIR)
};

declare function backup:trigger() {
    let $incremental := request:get-parameter("inc", ())
    let $params :=
        <parameters>
            <param name="output" value="{$backup:BACKUP_DIR}"/>
            <param name="backup" value="yes"/>
            <param name="incremental" value="{if ($incremental) then 'yes' else 'no'}"/>
        </parameters>
    return (
        system:trigger-system-task("org.exist.storage.ConsistencyCheckTask", $params),

            A backup has been triggered on the server. It will be processed once all running
            transactions have returned.

    )
};

declare function backup:display() {
    let $backupDir := backup:get-directory()
    return
        <form action="{session:encode-url(request:get-uri())}" method="GET">

Available DB Backups

                { backup:list-backups($backupDir) }
                <button class="refresh" type="submit" name="action" value="refresh">Refresh</button>

Trigger Backup

    	            <button type="submit" name="action" value="trigger">Trigger</button>

                <input type="checkbox" name="inc"/> Incremental
                <input type="hidden" name="panel" value="backup"/>

	    </form>
};

declare function backup:list-backups($dir as xs:string) as element(table) {

            Name
            Created
            Incremental

        {
            let $backups := backups:list($dir)/exist:backup
            return
                if (count($backups) eq 0) then

                        No backup archives found.

                else
                    for $backup in $backups
                    let $date := xs:dateTime($backup/exist:date)
                    let $download := concat(session:encode-url(xs:anyURI("backups/")), $backup/@file/string())
                    order by $date descending
                    return

                                {$backup/@file/string()}

                            {date:format-dateTime($date)}
                            {$backup/exist:incremental/text()}

        }

};

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

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

declare variable $backup:BACKUP_DIR := "export";

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

Backups

            {
                if ($action eq "trigger") then
                    backup:trigger()
                else
                    ()
            }
            { backup:display() }

};

declare function backup:get-directory() {
    let $home := system:get-exist-home()
    return
        if (ends-with($home, "WEB-INF")) then
            concat($home, "/data/", $backup:BACKUP_DIR)
        else
            concat($home, "/webapp/WEB-INF/data/", $backup:BACKUP_DIR)
};

declare function backup:trigger() {
    let $incremental := request:get-parameter("inc", ())
    let $params :=
        <parameters>
            <param name="output" value="{$backup:BACKUP_DIR}"/>
            <param name="backup" value="yes"/>
            <param name="incremental" value="{if ($incremental) then 'yes' else 'no'}"/>
        </parameters>
    return (
        system:trigger-system-task("org.exist.storage.ConsistencyCheckTask", $params),

            A backup has been triggered on the server. It will be processed once all running
            transactions have returned.

    )
};

declare function backup:display() {
    let $backupDir := backup:get-directory()
    return
        <form action="{session:encode-url(request:get-uri())}" method="GET">

Available DB Backups

                { backup:list-backups($backupDir) }
                <button class="refresh" type="submit" name="action" value="refresh">Refresh</button>
                <button type="submit" name="action" value="download">Download</button>

Trigger Backup

    	            <button type="submit" name="action" value="trigger">Trigger</button>

                <input type="checkbox" name="inc"/> Incremental
                <input type="hidden" name="panel" value="backup"/>

	    </form>
};

declare function backup:list-backups($dir as xs:string) as element(table) {

            Name
            Created
            Incremental

        {
            let $backups := backups:list($dir)/exist:backup
            return
                if (count($backups) eq 0) then

                        No backup archives found.

                else
                    for $backup in $backups
                    let $date := xs:dateTime($backup/exist:date)
                    let $download := concat(session:encode-url(xs:anyURI("backups/")), $backup/@file/string())
                    order by $date descending
                    return

                                {$backup/@file/string()}

                            {date:format-dateTime($date)}
                            {$backup/exist:incremental/text()}

        }

};


bug:38817 un-capitalize prefix for generated modules

(:
 Copyright 2002-2016 MarkLogic Corporation.  All Rights Reserved.

 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 "1.0-ml";

module namespace es-codegen = "http://marklogic.com/entity-services-codegen";

import module namespace esi = "http://marklogic.com/entity-services-impl"
    at "entity-services-impl.xqy";

declare namespace es = "http://marklogic.com/entity-services";
declare namespace tde = "http://marklogic.com/xdmp/tde";

(:~
 : Generates an XQuery module that can be customized and used
 : to support transforms associated with an entity type
 : @param $entity-type  An entity type object.
 : @return An XQuery module (text) that can be edited and installed in a modules database.
 :)
declare function es-codegen:conversion-module-generate(
    $entity-type as map:map
) as document-node()
{
    let $default-base-uri := "http://example.org/"
    let $info := map:get($entity-type, "info")
    let $title := map:get($info, "title")
    let $prefix := lower-case(substring($title,1,1)) || substring($title,2)
    let $version:= map:get($info, "version")
    let $definitions := map:get($entity-type, "definitions")
    let $base-uri := fn:head((map:get($info, "baseUri"), $default-base-uri))
    let $base-uri :=
            if (fn:matches($base-uri, "[#/]$"))
            then $base-uri
            else concat($base-uri, "#")
    return
document {
<conversion-module>
xquery version "1.0-ml";

(: This module was generated by MarkLogic Entity Services.
 : The source entity type document was {$title}-{$version}
 :
 : Modification History:
 :   Generated at timestamp: {fn:current-dateTime()}
 :   Persisted by AUTHOR
 :   Date: DATE
 :)
module namespace {$prefix} = "{$base-uri}{$title}-{$version}";

import module namespace es = "http://marklogic.com/entity-services"
    at "/MarkLogic/entity-services/entity-services.xqy";

(: extract-instance-{{entity-type}} Functions :)
(: These functions can be customized to reflect a data source for an entity type :)
{ (: iterate over entity types to make extract instance stubs :)
    for $entity-type-key in map:keys(map:get($entity-type, "definitions"))
    return
    <extract-instance>
declare function {$prefix}:extract-instance-{$entity-type-key}(
    $source-node as node()
) as map:map
{{
    let $instance := json:object()
    let $_ := map:put($instance, "$type", "{$entity-type-key}")
    let $_ := map:put($instance, "$attachments", $source-node)
    {
    let $this-type := map:get($definitions, $entity-type-key)
    let $properties-map := map:get($this-type, "properties")
    let $properties-keys := map:keys($properties-map)
    for $property-key in map:keys($properties-map)
    let $is-array := map:get(map:get($properties-map, $property-key), "datatype") eq "array"
    let $ref :=
        if ($is-array)
        then map:get(map:get(map:get($properties-map, $property-key), "items"), "$ref")
        else map:get(map:get($properties-map, $property-key), "$ref")
    let $path-to-property := concat("$source-node/", $entity-type-key, "/", $property-key)
    let $value :=
        if (empty($ref))
        then
            concat($path-to-property, " ! data(.)")
        else
            if(contains($ref, "#/definitions"))
            then
            concat("if (not(",
                    $path-to-property,
                    "/element()))
then ",
                    "data(", $path-to-property, ")",
                    "
else ",
                    $path-to-property,
                    " ! ",
                    $prefix,
                    ":extract-instance-",
                    replace($ref, "#/definitions/", ""),
                    "(.)"
                    )
            else
               concat($path-to-property, "/node()")

    return

    concat("let $_ := if (empty( (",
            $path-to-property,
            ")))
",
            "         then ()
",
            "         else map:put($instance, '", $property-key, "', ",$value, ")
   "
          )
    }
        return $instance
}};
    </extract-instance>/text()
}

(: instance-to-canonical-xml function
 : Depending on the relationships among your entity types
 : you may wish to modify sections of this function
 : to meet your own purposes.
 :)
declare function {$prefix}:instance-to-canonical-xml(
    $entity-instance as map:map
) as element(es:instance)
{{
    let $title := "{$title}"
    let $version := "{$version}"
    let $instance-keys := map:keys($entity-instance)
    let $instance-node :=
        (: Construct the instance wrapper element itself :)
        element es:instance {{
            (: Construct the metadata for the instance :)
            element es:info {{
                element es:title {{ $title }},
                element es:version {{ $version }}
                (: TODO id :)
            }},
            (: Construct an element that is named the same as the Entity Type :)
            element {{ map:get($entity-instance, "$type") }}  {{
                for $key in $instance-keys
                let $instance-property := map:get($entity-instance, $key)
                where ($key castable as xs:NCName and $key ne "$type")
                return
                    typeswitch ($instance-property)
                    (: This branch handles embedded objects.  You can choose to prune
                       an entity's representation of extend it with lookups here. :)
                    case json:object+
                        return
                            for $prop in $instance-property
                            return element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($prop)/(*[exists(./*)] except es:info) }}
                    (: A sequence of values should be simply treated as multiple elements :)
                    case item()+
                        return
                            for $val in $instance-property
                            return element {{ $key }} {{ $val }}
                    (: An array by convention can also treated as multiple elements :)
                    case json:array
                        return
                            for $val in json:array-values($instance-property)
                            return element {{ $key }} {{ $val }}
                    default return element {{ $key }} {{ $instance-property }}
            }}
        }}
    return $instance-node
}};

(: instance-to-envelope
 : This function is used to wrap sources and entity instances
 : within the same document
 :)
declare function {$prefix}:instance-to-envelope(
    $entity-instance as map:map
) as element(es:envelope)
{{
    element es:envelope {{
        {$prefix}:instance-to-canonical-xml($entity-instance),
        element es:attachments {{
            map:get($entity-instance, "$attachments")
        }}
    }}
}};

(: instance-from-document
 : if you have modified instance-to-envelope
 : you may need also to modify this function
 :)
declare function {$prefix}:instance-from-document(
    $document as document-node()
) as map:map*
{{
    let $xml-from-document := {$prefix}:instance-xml-from-document($document)
    for $root-instance in $xml-from-document
        let $instance := json:object()
        let $_ :=
            for $property in $root-instance/*
            return
                if ($property/element())
                then map:put($instance, local-name($property), $property/* ! {$prefix}:child-instance(.))
                else map:put($instance, local-name($property), data($property))
        return $instance
}};

declare function {$prefix}:child-instance(
    $element as element()
) as map:map*
{{
    let $child := json:object()
    let $_ :=
        for $property in $element/*
        return
            if ($property/element())
            then map:put($child, local-name($property), {$prefix}:child-instance($property))
            else map:put($child, local-name($property), data($property))
    return $child
}};

(:~
 : Returns all XML from within a document envelope except the es:info.
 : This function is generic enough not to require customization for
 : most entity type implementations.
 :)
declare function {$prefix}:instance-xml-from-document(
    $document as document-node()
) as element()
{{
    $document//es:instance/(* except es:info)
}};

declare function {$prefix}:instance-json-from-document(
    $document as document-node()
) as object-node()
{{
    let $instance := {$prefix}:instance-from-document($document)
    return xdmp:to-json($instance)/node()
}};

declare function {$prefix}:instance-get-attachments(
    $document as document-node()
) as element()*
{{
    $document//es:attachments/*
}};

</conversion-module>/text()
}

};

(:
 Copyright 2002-2016 MarkLogic Corporation.  All Rights Reserved.

 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 "1.0-ml";

module namespace es-codegen = "http://marklogic.com/entity-services-codegen";

import module namespace esi = "http://marklogic.com/entity-services-impl"
    at "entity-services-impl.xqy";

declare namespace es = "http://marklogic.com/entity-services";
declare namespace tde = "http://marklogic.com/xdmp/tde";

(:~
 : Generates an XQuery module that can be customized and used
 : to support transforms associated with an entity type
 : @param $entity-type  An entity type object.
 : @return An XQuery module (text) that can be edited and installed in a modules database.
 :)
declare function es-codegen:conversion-module-generate(
    $entity-type as map:map
) as document-node()
{
    let $default-base-uri := "http://example.org/"
    let $info := map:get($entity-type, "info")
    let $prefix := map:get($info, "title")
    let $version:= map:get($info, "version")
    let $definitions := map:get($entity-type, "definitions")
    let $base-uri := fn:head((map:get($info, "baseUri"), $default-base-uri))
    let $base-uri :=
            if (fn:matches($base-uri, "[#/]$"))
            then $base-uri
            else concat($base-uri, "#")
    return
document {
<conversion-module>
xquery version "1.0-ml";

(: This module was generated by MarkLogic Entity Services.
 : The source entity type document was {$prefix}-{$version}
 :
 : Modification History:
 :   Generated at timestamp: {fn:current-dateTime()}
 :   Persisted by AUTHOR
 :   Date: DATE
 :)
module namespace {$prefix} = "{$base-uri}{$prefix}-{$version}";

import module namespace es = "http://marklogic.com/entity-services"
    at "/MarkLogic/entity-services/entity-services.xqy";

(: extract-instance-{{entity-type}} Functions :)
(: These functions can be customized to reflect a data source for an entity type :)
{ (: iterate over entity types to make extract instance stubs :)
    for $entity-type-key in map:keys(map:get($entity-type, "definitions"))
    return
    <extract-instance>
declare function {$prefix}:extract-instance-{$entity-type-key}(
    $source-node as node()
) as map:map
{{
    let $instance := json:object()
    let $_ := map:put($instance, "$type", "{$entity-type-key}")
    let $_ := map:put($instance, "$attachments", $source-node)
    {
    let $this-type := map:get($definitions, $entity-type-key)
    let $properties-map := map:get($this-type, "properties")
    let $properties-keys := map:keys($properties-map)
    for $property-key in map:keys($properties-map)
    let $is-array := map:get(map:get($properties-map, $property-key), "datatype") eq "array"
    let $ref :=
        if ($is-array)
        then map:get(map:get(map:get($properties-map, $property-key), "items"), "$ref")
        else map:get(map:get($properties-map, $property-key), "$ref")
    let $path-to-property := concat("$source-node/", $entity-type-key, "/", $property-key)
    let $value :=
        if (empty($ref))
        then
            concat($path-to-property, " ! data(.)")
        else
            if(contains($ref, "#/definitions"))
            then
            concat("if (not(",
                    $path-to-property,
                    "/element()))
then ",
                    "data(", $path-to-property, ")",
                    "
else ",
                    $path-to-property,
                    " ! ",
                    $prefix,
                    ":extract-instance-",
                    replace($ref, "#/definitions/", ""),
                    "(.)"
                    )
            else
               concat($path-to-property, "/node()")

    return

    concat("let $_ := if (empty( (",
            $path-to-property,
            ")))
",
            "         then ()
",
            "         else map:put($instance, '", $property-key, "', ",$value, ")
   "
          )
    }
        return $instance
}};
    </extract-instance>/text()
}

(: instance-to-canonical-xml function
 : Depending on the relationships among your entity types
 : you may wish to modify sections of this function
 : to meet your own purposes.
 :)
declare function {$prefix}:instance-to-canonical-xml(
    $entity-instance as map:map
) as element(es:instance)
{{
    let $title := "{$prefix}"
    let $version := "{$version}"
    let $instance-keys := map:keys($entity-instance)
    let $instance-node :=
        (: Construct the instance wrapper element itself :)
        element es:instance {{
            (: Construct the metadata for the instance :)
            element es:info {{
                element es:title {{ $title }},
                element es:version {{ $version }}
                (: TODO id :)
            }},
            (: Construct an element that is named the same as the Entity Type :)
            element {{ map:get($entity-instance, "$type") }}  {{
                for $key in $instance-keys
                let $instance-property := map:get($entity-instance, $key)
                where ($key castable as xs:NCName and $key ne "$type")
                return
                    typeswitch ($instance-property)
                    (: This branch handles embedded objects.  You can choose to prune
                       an entity's representation of extend it with lookups here. :)
                    case json:object+
                        return
                            for $prop in $instance-property
                            return element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($prop)/(*[exists(./*)] except es:info) }}
                    (: A sequence of values should be simply treated as multiple elements :)
                    case item()+
                        return
                            for $val in $instance-property
                            return element {{ $key }} {{ $val }}
                    (: An array by convention can also treated as multiple elements :)
                    case json:array
                        return
                            for $val in json:array-values($instance-property)
                            return element {{ $key }} {{ $val }}
                    default return element {{ $key }} {{ $instance-property }}
            }}
        }}
    return $instance-node
}};

(: instance-to-envelope
 : This function is used to wrap sources and entity instances
 : within the same document
 :)
declare function {$prefix}:instance-to-envelope(
    $entity-instance as map:map
) as element(es:envelope)
{{
    element es:envelope {{
        {$prefix}:instance-to-canonical-xml($entity-instance),
        element es:attachments {{
            map:get($entity-instance, "$attachments")
        }}
    }}
}};

(: instance-from-document
 : if you have modified instance-to-envelope
 : you may need also to modify this function
 :)
declare function {$prefix}:instance-from-document(
    $document as document-node()
) as map:map*
{{
    let $xml-from-document := {$prefix}:instance-xml-from-document($document)
    for $root-instance in $xml-from-document
        let $instance := json:object()
        let $_ :=
            for $property in $root-instance/*
            return
                if ($property/element())
                then map:put($instance, local-name($property), $property/* ! {$prefix}:child-instance(.))
                else map:put($instance, local-name($property), data($property))
        return $instance
}};

declare function {$prefix}:child-instance(
    $element as element()
) as map:map*
{{
    let $child := json:object()
    let $_ :=
        for $property in $element/*
        return
            if ($property/element())
            then map:put($child, local-name($property), {$prefix}:child-instance($property))
            else map:put($child, local-name($property), data($property))
    return $child
}};

(:~
 : Returns all XML from within a document envelope except the es:info.
 : This function is generic enough not to require customization for
 : most entity type implementations.
 :)
declare function {$prefix}:instance-xml-from-document(
    $document as document-node()
) as element()
{{
    $document//es:instance/(* except es:info)
}};

declare function {$prefix}:instance-json-from-document(
    $document as document-node()
) as object-node()
{{
    let $instance := {$prefix}:instance-from-document($document)
    return xdmp:to-json($instance)/node()
}};

declare function {$prefix}:instance-get-attachments(
    $document as document-node()
) as element()*
{{
    $document//es:attachments/*
}};

</conversion-module>/text()
}

};


[testing] some fixes to the XQuery test runner: create in-memory copy of the test document to avoid issues if it is removed by one of the tests. Fix variable declarations.

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

xquery version "1.0";

module namespace t="http://exist-db.org/xquery/testing";

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

declare function t:setup-action($action) {
    typeswitch ($action)
        case element(create-collection) return
            xdb:create-collection($action/@parent, $action/@name)
        case element(store) return
			t:store($action)
        case element(remove-collection) return
            xdb:remove($action/@collection)
        case element(remove-document) return
            xdb:remove($action/@collection, $action/@name)
        default return
            ()
};

declare function t:store($action as element(store)) {
    let $type := if ($action/@type) then $action/@type/string() else "application/xml"
    let $data :=
		if ($action/*) then
			$action/*[1]
		else
			$action/string()
	return
        xdb:store($action/@collection, $action/@name, $data, $type)
};

declare function t:setup($setup as element(setup)) {
    for $action in $setup/*
    return
        t:setup-action($action)
};

declare function t:tearDown($tearDown as element(tearDown)?) {
    for $action in $tearDown/*
    return
        t:setup-action($action)
};

declare function t:declare-variable($var as element(variable)) as item()? {
    let $children := $var/*
    return
        if (empty($children)) then
            string-join($var/node(), '')
        else
            util:serialize($children, ())
};

declare function t:init-prolog($test as element(test)) {
	let $imports := $test/../imports
	let $vars :=
	    string-join(
        	for $var in $test/../variable
        	return
        	    concat("declare variable $", $var/@name, " := ", t:declare-variable($var), ";"),
            ""
        )
	return
		string-join(($imports, $vars, $test/../functions), '')
};

declare function t:run-test($test as element(test), $count as xs:integer) {
	let $context := t:init-prolog($test)
    let $output :=
		util:catch("*",
			util:eval(concat($context, $test/code/string())),
			<error>Compilation error: {$util:exception-message}</error>
		)
    let $expected :=
        if ($test/@output eq 'text') then
            data($test/expected)
        else $test/expected/node()
    let $OK :=
        if ($test/xpath) then
            exists(t:xpath($output, $test/xpath))
        else if ($test/@output eq 'text') then
            normalize-space(string-join(for $x in $output return string($x),' ')) eq normalize-space($expected)
        else
            deep-equal($output, $expected)
    let $expanded :=
		if ($output instance of node()) then
        	util:expand($output)
		else
			$output
    return
        <test n="{$count}" pass="{$OK}">
        {
            if (not($OK)) then
                ($test/task, $test/expected, <result>{$expanded}</result>)
            else ()
        }
        </test>
};

declare function t:xpath($output as item()*, $xpath as element()) {
    for $prefix in in-scope-prefixes($xpath)
    let $nsuri := namespace-uri-for-prefix($prefix, $xpath)
    return
        if ($prefix != 'xml') then
        util:declare-namespace($prefix, $nsuri)
        else (),
    util:eval(concat("$output", $xpath))
};

declare function t:run-testSet($set as element(TestSet)) {
    let $copy := util:expand($set)
    let $null := t:setup($copy/setup)
    let $result := util:expand(
           <TestSet>
           {$copy/testName}
           {$copy/description}
           {
               for $test at $p in $copy/test
               return
                   t:run-test($test, $p)
           }
           </TestSet>
        )
    let $null := t:tearDown($copy/tearDown)
    return $result
};

declare function t:format-testResult($result) {
    let $formatted :=

{$result/testName}

{$result/description/p}

          {for $test in $result//test
           return

                    {$test/@n/.}
                    {$test/@pass/.}

          }

     return
        $formatted
};

xquery version "1.0";

module namespace t="http://exist-db.org/xquery/testing";

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

declare function t:setup-action($action) {
    typeswitch ($action)
        case element(create-collection) return
            xdb:create-collection($action/@parent, $action/@name)
        case element(store) return
			t:store($action)
        case element(remove-collection) return
            xdb:remove($action/@collection)
        default return
            ()
};

declare function t:store($action as element(store)) {
    let $type := if ($action/@type) then $action/@type/string() else "application/xml"
    let $data :=
		if ($action/*) then
			$action/*[1]
		else
			$action/string()
	return
        xdb:store($action/@collection, $action/@name, $data, $type)
};

declare function t:setup($setup as element(setup)) {
    for $action in $setup/*
    return
        t:setup-action($action)
};

declare function t:tearDown($tearDown as element(tearDown)?) {
    for $action in $tearDown/*
    return
        t:setup-action($action)
};

declare function t:init-prolog($test as element(test)) {
	let $imports := $test/../imports
	let $vars :=
	    string-join(
        	for $var in $test/../variable
        	return
        	    concat("declare variable $", $var/@name, " := ", util:serialize($var/*, ()), ";"),
            ""
        )
	return
		string-join(($imports, $vars, $test/../functions), '')
};

declare function t:run-test($test as element(test), $count as xs:integer) {
	let $context := t:init-prolog($test)
    let $output :=
		util:catch("*",
			util:eval(concat($context, $test/code/string())),
			<error>Compilation error: {$util:exception-message}</error>
		)
    let $expected :=
        if ($test/@output eq 'text') then
            data($test/expected)
        else $test/expected/node()
    let $OK :=
        if ($test/xpath) then
            exists(t:xpath($output, $test/xpath))
        else if ($test/@output eq 'text') then
            normalize-space(string-join(for $x in $output return string($x),' ')) eq normalize-space($expected)
        else
            deep-equal($output, $expected)
    let $expanded :=
		if ($output instance of node()) then
        	util:expand($output)
		else
			$output
    return
        <test n="{$count}" pass="{$OK}">
        {
            if (not($OK)) then
                ($test/task, $test/expected, <result>{$expanded}</result>)
            else ()
        }
        </test>
};

declare function t:xpath($output as item()*, $xpath as element()) {
    for $prefix in in-scope-prefixes($xpath)
    let $nsuri := namespace-uri-for-prefix($prefix, $xpath)
    return
        if ($prefix != 'xml') then
        util:declare-namespace($prefix, $nsuri)
        else (),
    util:eval(concat("$output", $xpath))
};

declare function t:run-testSet($set as element(TestSet)) {
    let $null := t:setup($set/setup)
    let $result :=
        <TestSet>
        {$set/testName}
        {$set/description}
        {
            for $test at $p in $set/test
            return
                t:run-test($test, $p)
        }
        </TestSet>
    let $null := t:tearDown($set/tearDown)
    return $result
};

declare function t:format-testResult($result) {
    let $formatted :=

{$result/testName}

{$result/description/p}

          {for $test in $result//test
           return

                    {$test/@n/.}
                    {$test/@pass/.}

          }

     return
        $formatted
};


Remove IE rem polyfill

Remove IE rem polyfill

xquery version "1.0" encoding "utf-8";

import module namespace calli = "http://callimachusproject.org/rdf/2009/framework#" at "/callimachus/layout-functions.xq";

    <meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0,target-densityDpi=device-dpi"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <link rel="icon" href="/favicon.ico" />

    {calli:styles()}
    {calli:scripts()}

    {calli:head()}

    {calli:bodyAttributes()}

                    {calli:home(Callimachus)}
                    <menu type="toolbar" class="nav pull-right">

                            {calli:login(Sign in)}

                            <menu type="list" class="dropdown-menu">

{calli:folder(Home folder)}

{calli:changes(Recent changes)}

About Callimachus

Getting started

Send feedback

                                {calli:pageLinks(

,
)}

{calli:whatlinkshere(What links here)}

{calli:relatedchanges(Related changes)}

{calli:permissions(Permissions)}

{calli:introspect(Introspect resource)}

Print this page

{calli:profile(Account)}

{calli:logout(Sign out)}

                            </menu>

                    </menu>

{calli:lookup('Lookup...')}

            {calli:breadcrumb(»)}
            {calli:hgroup()}
            {calli:sidebar(
)}

                {calli:activateNav(
                    View
                    Edit
                    Discussion
                    Describe
                    History
                )}

                    {calli:error(

                        <button type="button" class="close" data-dismiss="alert">×</button>

Oops!

)}
                    {calli:content()}

                {calli:generator(
)}
                {calli:lastmod(
This resource was last modified at <time class="abbreviated"/>
)}


*	Prediction and evaluation job scheduling now understands and handles the accepted queries answer.

git-svn-id: b46a086423077f2361295c5ec15b0f9cbe8e278c@1842 b091869f-ef14-0410-ae3d-fae7310851ef


adapting output-format variables

adapting output-format variables

module namespace repo-utils = "http://aac.ac.at/content_repository/utils";

import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace diag =  "http://www.loc.gov/zing/srw/diagnostic/" at  "modules/diagnostics/diagnostics.xqm";

(:~ HELPER functions - configuration, caching, data-access
:)

(:
: this all cannot be defined as global variable, because we want different configurations,
: thus the $config has to be sent as param everywhere
: declare variable $repo-utils:config := doc("config.xml");
: declare variable $repo-utils:mappings := doc(repo-utils:config-value('mappings'));
: declare variable $repo-utils:data-collection := collection(repo-utils:config-value('data.path'));
: declare variable $repo-utils:md-collection := collection(repo-utils:config-value('metadata.path'));
: declare variable $repo-utils:cachePath as xs:string := repo-utils:config-value('cache.path');
:)

declare variable $repo-utils:xmlExt as xs:string := ".xml";
declare variable $repo-utils:responseFormatXml as xs:string := "xml";
declare variable $repo-utils:responseFormatJSon as xs:string := "json";
declare variable $repo-utils:responseFormatText as xs:string := "text";
declare variable $repo-utils:responseFormatHTML as xs:string := "html";
declare variable $repo-utils:responseFormatHTMLpage as xs:string := "htmlpage";

declare function repo-utils:config-value($config, $key as xs:string) as xs:string* {
    $config//property[@key=$key]
};

(:~ Get value of a param based on a key, from config or from request-param (precedence) :)
declare function repo-utils:param-value($config, $key as xs:string, $default as xs:string) as xs:string* {

    let $param := request:get-parameter($key, $default)
    return if ($param) then $param else $config//property[@key=$key]
};

(:~ returns db-collection (as nodeset) based on the identifier in x-context, looked up in the mapping or default collection as defined in config

@returns nodeset of given context
 if no x-context match or no context provided returns default collection from the config (data.path )
 (if available, otherwise again empty result)

WATCHME: changed to lax handling of the context (if no match - go to default)
        gives better recall, but may confuse - alternatively: strict: empty result if x-context does not match
TODO: accept $x-context as xs:string*
:)
declare function repo-utils:context-to-collection($x-context as xs:string, $config) as node()* {
(:      let $mappings := doc(repo-utils:config-value($config, 'mappings')):)
      let $dbcoll-path := repo-utils:context-to-collection-path($x-context, $config)
    return if ($dbcoll-path eq "" ) then ()
                else collection($dbcoll-path)
};

(:~ returns path to db-collection (as nodeset) based on the identifier in x-context,
looked up in the mapping or default data.path as defined in config

@returns dbcoll-path of given context
 if no x-context match or no context provided returns default collection from the config (data.path )
 (if available, otherwise again empty result)

WATCHME: changed to lax handling of the context (if no match - go to default)
        gives better recall, but may confuse - alternatively: strict: empty result if x-context does not match
changed again: only give default if x-context is empty string or 'default'-string.
T
:)
declare function repo-utils:context-to-collection-path($x-context as xs:string, $config) as xs:string {
      let $mappings:= doc(repo-utils:config-value($config, 'mappings'))
    return    (: if ($x-context) then :)
            if (exists($mappings//map[xs:string(@key) eq $x-context]/@path)) then
                    $mappings//map[xs:string(@key) eq $x-context]/xs:string(@path)
                (: else "" :)
                  else if (exists(repo-utils:config-value($config, 'data.path')) and
                            ($x-context = ('', 'default'))) then
                        repo-utils:config-value($config, 'data.path')
                  else ""
};

(:~ Get the resource by PID/handle/URL or some known identifier.
  TODO: NOT ADAPTED YET! (taken from CMD)
  TODO: be clear about resource itself and metadata-record!
:)
(:declare function repo-utils:get-resource-by-id($id as xs:string) as node()* {
  let $collection := collection($cr:dataPath)
  return
    if ($id eq "" or $id eq $cr:collectionRoot) then
    $collection//IsPartOf[. = $cr:collectionRoot]/ancestor::CMD
  else
    util:eval(concat("$collection/ft:query(descendant::MdSelfLink, <term>", xdb:decode($id), "</term>)/ancestor::CMD"))
 (\: $collection/descendant::MdSelfLink[. = xdb:decode($id)]/ancestor::CMD :\)
};
:)

(:~ Checks whether the document is available or not.
  generic, currently not used
:)
declare function repo-utils:is-doc-available($collection as xs:string, $doc-name as xs:string) as xs:boolean {
  fn:doc-available(fn:concat($collection, "/", $doc-name))
};

declare function repo-utils:is-in-cache($doc-name as xs:string,$config) as xs:boolean {
  fn:doc-available(fn:concat(repo-utils:config-value($config, 'cache.path'), "/", $doc-name))
};

declare function repo-utils:get-from-cache($doc-name as xs:string,$config) as item()* {
      fn:doc(fn:concat(repo-utils:config-value($config, 'cache.path'), "/", $doc-name))
};

(:~ Store the data in cache. Uses own writer-account
:)
declare function repo-utils:store-in-cache($doc-name as xs:string, $data as node(),$config) as item()* {
  let $clarin-writer := fn:doc("/db/cr/writer.xml"),
  $cache-path := repo-utils:config-value($config, 'cache.path'),
  $dummy := xdb:login($cache-path, $clarin-writer//write-user/text(), $clarin-writer//write-user-cred/text()),
  $store := (: util:catch("org.exist.xquery.XPathException", :) xdb:store($cache-path, $doc-name, $data), (: , ()) :)
  $stored-doc := fn:doc(concat($cache-path, "/", $doc-name))
  return $stored-doc
(:  ():)
};

(:
this tries to create sub-collections in index for
individual data-collection - but it makes the retrieval etc. also more complicated
so rather encoding the data-collection also in the name

declare function repo-utils:store-in-cache($data-collection as item(), $doc-name as xs:string, $data as node()) as item()* {
    let $data-coll-name := collection-name($data-collection)
    let $index-coll-path := concat($repo-utils:cachePath, "/", $data-coll-name )
   let $create-coll := if (not(xmldb:collection-available($index-coll-path ))) then
                           xmldb:create-collection($repo-utils:cachePath, $data-collname) else ()
  let $store-result := repo-utils:store($index-coll-path, $doc-name, $data, true())

return $store-result
};
:)

(:<options><option key="update">yes</option></options>:)
declare function repo-utils:store($collection as xs:string, $doc-name as xs:string, $data as node(), $overwrite as xs:boolean) as item()* {
  let $clarin-writer := fn:doc("/db/cr/writer.xml"),
  $dummy := xdb:login($collection, $clarin-writer//write-user/text(), $clarin-writer//write-user-cred/text())

  let $rem := if ($overwrite and doc-available(concat($collection, $doc-name))) then xdb:remove($collection, $doc-name) else ()

  let $store := (: util:catch("org.exist.xquery.XPathException", :) xdb:store($collection, $doc-name, $data), (: , ()) :)
  $stored-doc := fn:doc(concat($collection, "/", $doc-name))
  return $stored-doc
};

declare function repo-utils:gen-cache-id($type-name as xs:string, $keys as xs:string+, $depth as xs:string) as xs:string {
    repo-utils:gen-cache-id($type-name , ($keys, $depth) )
};
(:~ Create document name with md5-hash for selected collections (or types) for reuse.
:)
declare function repo-utils:gen-cache-id($type-name as xs:string, $keys as xs:string+) as xs:string {
       let $sanitized-names := for $key in $keys return repo-utils:sanitize-name($key)
    return
(:    fn:concat($name-prefix, "-", util:hash(string-join($sorted-names, ""), "MD5"), $repo-utils:xmlExt):)
    fn:concat($type-name, "-", string-join($sanitized-names, "-"), $repo-utils:xmlExt)
};

(:~ wipes out problematic characters from names
:)
declare function repo-utils:sanitize-name($name as xs:string) as xs:string {
    translate($name, ":/",'_')
};

declare function repo-utils:serialise-as($item as node()?, $format as xs:string, $operation as xs:string, $config) as item()? {
    repo-utils:serialise-as($item, $format, $operation, $config, ())
};

(:~ transform result to HTML, JSON, or leave as XML - according to format parameter

@param $parameters optional additional parameters to be passed to xsl
:)
declare function repo-utils:serialise-as($item as node()?, $format as xs:string, $operation as xs:string, $config, $parameters as node()* ) as item()? {
        if ($format eq $repo-utils:responseFormatJSon) then
	       let $option := util:declare-option("exist:serialize", "method=json media-type=application/json")
	       return $item
	    else if (contains($format, $repo-utils:responseFormatHTML)) then
	           let $xslDoc := doc(concat(repo-utils:config-value($config, 'scripts.path'), repo-utils:config-value($config, concat($operation, ".xsl"))) )
	           let $res := transform:transform($item,$xslDoc,
              			<parameters><param name="format" value="{$format}"/>
              			            <param name="x-context" value="{repo-utils:param-value($config, 'x-context', '' )}"/>
              			            <param name="base_url" value="{repo-utils:config-value($config, 'base.url')}"/>
              			            <param name="mappings-file" value="{repo-utils:config-value($config, 'mappings')}"/>
              			            <param name="scripts_url" value="{repo-utils:config-value($config, 'scripts.url')}"/>
              			             <param name="site_name" value="{repo-utils:config-value($config, 'site.name')}"/>
              			             <param name="site_logo" value="{repo-utils:config-value($config, 'site.logo')}"/>
              			             {$parameters/param}
              			</parameters>)
(:               let $option := util:declare-option("exist:serialize", "method=xml media-type=text/html"):)
let $option := util:declare-option("exist:serialize", "method=xhtml media-type=text/html")
	           return $res
	   else
	       let $option := util:declare-option("exist:serialize", "method=xml media-type=application/xml")
	    return $item
};
(: $repo-utils:responseFormatXml, $repo-utils:responseFormatText:)

	    (:let $option :=
	              if (contains($format, $repo-utils:responseFormatHTML)) then
	                  util:declare-option("exist:serialize", "method=xml media-type=text/xhtml")
	              else
    	              util:declare-option("exist:serialize", "method=xml media-type=application/xml")
:)

	          	(: $item :)

module namespace repo-utils = "http://aac.ac.at/content_repository/utils";

import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace diag =  "http://www.loc.gov/zing/srw/diagnostic/" at  "modules/diagnostics/diagnostics.xqm";

(:~ HELPER functions - configuration, caching, data-access
:)

(:
: this all cannot be defined as global variable, because we want different configurations,
: thus the $config has to be sent as param everywhere
: declare variable $repo-utils:config := doc("config.xml");
: declare variable $repo-utils:mappings := doc(repo-utils:config-value('mappings'));
: declare variable $repo-utils:data-collection := collection(repo-utils:config-value('data.path'));
: declare variable $repo-utils:md-collection := collection(repo-utils:config-value('metadata.path'));
: declare variable $repo-utils:cachePath as xs:string := repo-utils:config-value('cache.path');
:)

declare variable $repo-utils:xmlExt as xs:string := ".xml";
declare variable $repo-utils:responseFormatXml as xs:string := "xml";
declare variable $repo-utils:responseFormatJSon as xs:string := "json";
declare variable $repo-utils:responseFormatText as xs:string := "text";
declare variable $repo-utils:responseFormatHTML as xs:string := "htmlpage";

declare function repo-utils:config-value($config, $key as xs:string) as xs:string* {
    $config//property[@key=$key]
};

(:~ Get value of a param based on a key, from config or from request-param (precedence) :)
declare function repo-utils:param-value($config, $key as xs:string, $default as xs:string) as xs:string* {

    let $param := request:get-parameter($key, $default)
    return if ($param) then $param else $config//property[@key=$key]
};

(:~ returns db-collection (as nodeset) based on the identifier in x-context, looked up in the mapping or default collection as defined in config

@returns nodeset of given context
 if no x-context match or no context provided returns default collection from the config (data.path )
 (if available, otherwise again empty result)

WATCHME: changed to lax handling of the context (if no match - go to default)
        gives better recall, but may confuse - alternatively: strict: empty result if x-context does not match
TODO: accept $x-context as xs:string*
:)
declare function repo-utils:context-to-collection($x-context as xs:string, $config) as node()* {
(:      let $mappings := doc(repo-utils:config-value($config, 'mappings')):)
      let $dbcoll-path := repo-utils:context-to-collection-path($x-context, $config)
    return if ($dbcoll-path eq "" ) then ()
                else collection($dbcoll-path)
};

(:~ returns path to db-collection (as nodeset) based on the identifier in x-context,
looked up in the mapping or default data.path as defined in config

@returns dbcoll-path of given context
 if no x-context match or no context provided returns default collection from the config (data.path )
 (if available, otherwise again empty result)

WATCHME: changed to lax handling of the context (if no match - go to default)
        gives better recall, but may confuse - alternatively: strict: empty result if x-context does not match
changed again: only give default if x-context is empty string or 'default'-string.
T
:)
declare function repo-utils:context-to-collection-path($x-context as xs:string, $config) as xs:string {
      let $mappings:= doc(repo-utils:config-value($config, 'mappings'))
    return    (: if ($x-context) then :)
            if (exists($mappings//map[xs:string(@key) eq $x-context]/@path)) then
                    $mappings//map[xs:string(@key) eq $x-context]/xs:string(@path)
                (: else "" :)
                  else if (exists(repo-utils:config-value($config, 'data.path')) and
                            ($x-context = ('', 'default'))) then
                        repo-utils:config-value($config, 'data.path')
                  else ""
};

(:~ Get the resource by PID/handle/URL or some known identifier.
  TODO: NOT ADAPTED YET! (taken from CMD)
  TODO: be clear about resource itself and metadata-record!
:)
(:declare function repo-utils:get-resource-by-id($id as xs:string) as node()* {
  let $collection := collection($cr:dataPath)
  return
    if ($id eq "" or $id eq $cr:collectionRoot) then
    $collection//IsPartOf[. = $cr:collectionRoot]/ancestor::CMD
  else
    util:eval(concat("$collection/ft:query(descendant::MdSelfLink, <term>", xdb:decode($id), "</term>)/ancestor::CMD"))
 (\: $collection/descendant::MdSelfLink[. = xdb:decode($id)]/ancestor::CMD :\)
};
:)

(:~ Checks whether the document is available or not.
  generic, currently not used
:)
declare function repo-utils:is-doc-available($collection as xs:string, $doc-name as xs:string) as xs:boolean {
  fn:doc-available(fn:concat($collection, "/", $doc-name))
};

declare function repo-utils:is-in-cache($doc-name as xs:string,$config) as xs:boolean {
  fn:doc-available(fn:concat(repo-utils:config-value($config, 'cache.path'), "/", $doc-name))
};

declare function repo-utils:get-from-cache($doc-name as xs:string,$config) as item()* {
      fn:doc(fn:concat(repo-utils:config-value($config, 'cache.path'), "/", $doc-name))
};

(:~ Store the data in cache. Uses own writer-account
:)
declare function repo-utils:store-in-cache($doc-name as xs:string, $data as node(),$config) as item()* {
  let $clarin-writer := fn:doc("/db/cr/writer.xml"),
  $cache-path := repo-utils:config-value($config, 'cache.path'),
  $dummy := xdb:login($cache-path, $clarin-writer//write-user/text(), $clarin-writer//write-user-cred/text()),
  $store := (: util:catch("org.exist.xquery.XPathException", :) xdb:store($cache-path, $doc-name, $data), (: , ()) :)
  $stored-doc := fn:doc(concat($cache-path, "/", $doc-name))
  return $stored-doc
(:  ():)
};

(:
this tries to create sub-collections in index for
individual data-collection - but it makes the retrieval etc. also more complicated
so rather encoding the data-collection also in the name

declare function repo-utils:store-in-cache($data-collection as item(), $doc-name as xs:string, $data as node()) as item()* {
    let $data-coll-name := collection-name($data-collection)
    let $index-coll-path := concat($repo-utils:cachePath, "/", $data-coll-name )
   let $create-coll := if (not(xmldb:collection-available($index-coll-path ))) then
                           xmldb:create-collection($repo-utils:cachePath, $data-collname) else ()
  let $store-result := repo-utils:store($index-coll-path, $doc-name, $data, true())

return $store-result
};
:)

(:<options><option key="update">yes</option></options>:)
declare function repo-utils:store($collection as xs:string, $doc-name as xs:string, $data as node(), $overwrite as xs:boolean) as item()* {
  let $clarin-writer := fn:doc("/db/cr/writer.xml"),
  $dummy := xdb:login($collection, $clarin-writer//write-user/text(), $clarin-writer//write-user-cred/text())

  let $rem := if ($overwrite and doc-available(concat($collection, $doc-name))) then xdb:remove($collection, $doc-name) else ()

  let $store := (: util:catch("org.exist.xquery.XPathException", :) xdb:store($collection, $doc-name, $data), (: , ()) :)
  $stored-doc := fn:doc(concat($collection, "/", $doc-name))
  return $stored-doc
};

declare function repo-utils:gen-cache-id($type-name as xs:string, $keys as xs:string+, $depth as xs:string) as xs:string {
    repo-utils:gen-cache-id($type-name , ($keys, $depth) )
};
(:~ Create document name with md5-hash for selected collections (or types) for reuse.
:)
declare function repo-utils:gen-cache-id($type-name as xs:string, $keys as xs:string+) as xs:string {
       let $sanitized-names := for $key in $keys return repo-utils:sanitize-name($key)
    return
(:    fn:concat($name-prefix, "-", util:hash(string-join($sorted-names, ""), "MD5"), $repo-utils:xmlExt):)
    fn:concat($type-name, "-", string-join($sanitized-names, "-"), $repo-utils:xmlExt)
};

(:~ wipes out problematic characters from names
:)
declare function repo-utils:sanitize-name($name as xs:string) as xs:string {
    translate($name, ":/",'_')
};

declare function repo-utils:serialise-as($item as node()?, $format as xs:string, $operation as xs:string, $config) as item()? {
    repo-utils:serialise-as($item, $format, $operation, $config, ())
};

(:~ transform result to HTML, JSON, or leave as XML - according to format parameter

@param $parameters optional additional parameters to be passed to xsl
:)
declare function repo-utils:serialise-as($item as node()?, $format as xs:string, $operation as xs:string, $config, $parameters as node()* ) as item()? {
        if ($format eq $repo-utils:responseFormatJSon) then
	       let $option := util:declare-option("exist:serialize", "method=json media-type=application/json")
	       return $item
	    else if (contains($format, $repo-utils:responseFormatHTML)) then
	           let $xslDoc := doc(concat(repo-utils:config-value($config, 'scripts.path'), repo-utils:config-value($config, concat($operation, ".xsl"))) )
	           let $res := transform:transform($item,$xslDoc,
              			<parameters><param name="format" value="{$format}"/>
              			            <param name="x-context" value="{repo-utils:param-value($config, 'x-context', '' )}"/>
              			            <param name="base_url" value="{repo-utils:config-value($config, 'base.url')}"/>
              			            <param name="mappings-file" value="{repo-utils:config-value($config, 'mappings')}"/>
              			            <param name="scripts_url" value="{repo-utils:config-value($config, 'scripts.url')}"/>
              			             <param name="site_name" value="{repo-utils:config-value($config, 'site.name')}"/>
              			             <param name="site_logo" value="{repo-utils:config-value($config, 'site.logo')}"/>
              			             {$parameters/param}
              			</parameters>)
(:               let $option := util:declare-option("exist:serialize", "method=xml media-type=text/html"):)
let $option := util:declare-option("exist:serialize", "method=xhtml media-type=text/html")
	           return $res
	   else
	       let $option := util:declare-option("exist:serialize", "method=xml media-type=application/xml")
	    return $item
};
(: $repo-utils:responseFormatXml, $repo-utils:responseFormatText:)

	    (:let $option :=
	              if (contains($format, $repo-utils:responseFormatHTML)) then
	                  util:declare-option("exist:serialize", "method=xml media-type=text/xhtml")
	              else
    	              util:declare-option("exist:serialize", "method=xml media-type=application/xml")
:)

	          	(: $item :)


added endpoints to manage local cache of remote directories to documents.json

module namespace page = 'http://basex.org/modules/web-page';

import module namespace csd_lsd = "https://github.com/openhie/openinfoman/csd_lsd";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_psd = "https://github.com/openhie/openinfoman/csd_psd";
declare   namespace   csd = "urn:ihe:iti:csd:2013";

declare
  %rest:path("/CSD/initSampleDirectory/directory/{$name}")
  %rest:GET
  %output:method("xhtml")
  function page:get_service_menu($name)
{
  let $response := page:services_menu($name)
  return csd_webui:nocache(csd_webui:wrapper($response))
};

declare
  %rest:path("/CSD/initSampleDirectory/directory/{$name}/get")
  %rest:GET
  function page:get_directory($name)
{
  csd_dm:open_document($name)
};

declare
  %rest:path("/CSD/directory/{$name}/get")
  %rest:GET
  function page:get_directory2($name)
{
  csd_dm:open_document($name)
};

declare
  %rest:path("/CSD/directory/{$name}/get/{$entity}/{$entityID}")
  %rest:GET
  function page:get_entity($name,$entity,$entityID)
{
  let $doc := csd_dm:open_document($name)
  let $entities:=
    switch($entity)
    case "provider" return $doc/csd:CSD/csd:providerDirectory/csd:provider
    case "facility" return $doc/csd:CSD/csd:facilityDirectory/csd:facility
    case "organization" return $doc/csd:CSD/csd:organizationDirectory/csd:organization
    case "service" return $doc/csd:CSD/csd:serviceDirectory/csd:service
    default return ()

  return  $entities[@entityID = $entityID]

};

declare updating
  %rest:path("/CSD/initSampleDirectory/directory/{$name}/load")
  %rest:GET
  function page:load($name)
{
(
  csd_lsd:load($name)   ,
  csd_webui:redirect_out("CSD/initSampleDirectory")
)
};

declare updating
  %rest:path("/CSD/initSampleDirectory/directory/{$name}/reload")
  %rest:GET
  function page:reload($name)
{
(
  csd_dm:empty($name)   ,
  csd_webui:redirect_out(("CSD/initSampleDirectory/directory/",$name,"/load"))
)

};

declare
  %rest:path("/CSD/initSampleDirectory")
  %rest:GET
  %output:method("xhtml")
  function page:directory_list()
{
let $response :=

Sample Directories

	    {for $name in csd_lsd:sample_directories()
	    order by $name
	    return

	      {$name}

	      {page:services_menu($name)}

	    }

return csd_webui:nocache(  csd_webui:wrapper($response))

};

declare
  %rest:path("/CSD/documents.json")
  %rest:GET
  function page:export_function_details_json(){
  (<rest:response>
    <output:serialization-parameters>
      <output:media-type value='application/json'/>
    </output:serialization-parameters>
  </rest:response>,
  xml-to-json( page:get_export_document_details())
    )
};

declare
  %rest:path("/CSD/documents.xml")
  %rest:GET
  function page:export_document_details_xml(){

    page:get_export_document_details()
};

declare function page:get_export_document_details() {
  <map xmlns="http://www.w3.org/2005/xpath-functions">
    {
      let $remote_docs :=  csd_psd:registered_directories()
      return
        for $name in csd_dm:registered_documents()
	return
	<map key="{string($name)}">
	  <string key="careServicesRequest">{csd_webui:generateURL(('CSD/csr/',$name,'/careServicesRequest'))}</string>
	  <map key="careServicesRequests">
	    {
	      for $function in (csr_proc:stored_functions(),csr_proc:stored_updating_functions())
	      let $urn:= string($function/@urn)
	      return <string key="{$urn}">{csd_webui:generateURL(('CSD/csr/',$name,'/careServicesRequest/',$urn))}</string>
	    }
	  </map>
	  {
	    if ($name = $remote_docs)
	    then
	      <map key="cache">
	        <string key="update">{csd_webui:generateURL(("/CSD/pollService/directory" ,$name , "update_cache"))}</string>
	        <string key="empty">{csd_webui:generateURL(("/CSD/pollService/directory" ,$name , "empty_cache"))}</string>
	      </map>
	    else ()
	  }
	</map>
    }
  </map>
};

declare function page:services_menu($name) {

    {if (not(csd_dm:document_source_exists($name))) then

Initialize  {$name}

  else
    (

Get  {$name}
,

Reload {$name}

  )
    }

};

module namespace page = 'http://basex.org/modules/web-page';

import module namespace csd_lsd = "https://github.com/openhie/openinfoman/csd_lsd";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
declare   namespace   csd = "urn:ihe:iti:csd:2013";

declare
  %rest:path("/CSD/initSampleDirectory/directory/{$name}")
  %rest:GET
  %output:method("xhtml")
  function page:get_service_menu($name)
{
  let $response := page:services_menu($name)
  return csd_webui:nocache(csd_webui:wrapper($response))
};

declare
  %rest:path("/CSD/initSampleDirectory/directory/{$name}/get")
  %rest:GET
  function page:get_directory($name)
{
  csd_dm:open_document($name)
};

declare
  %rest:path("/CSD/directory/{$name}/get")
  %rest:GET
  function page:get_directory2($name)
{
  csd_dm:open_document($name)
};

declare
  %rest:path("/CSD/directory/{$name}/get/{$entity}/{$entityID}")
  %rest:GET
  function page:get_entity($name,$entity,$entityID)
{
  let $doc := csd_dm:open_document($name)
  let $entities:=
    switch($entity)
    case "provider" return $doc/csd:CSD/csd:providerDirectory/csd:provider
    case "facility" return $doc/csd:CSD/csd:facilityDirectory/csd:facility
    case "organization" return $doc/csd:CSD/csd:organizationDirectory/csd:organization
    case "service" return $doc/csd:CSD/csd:serviceDirectory/csd:service
    default return ()

  return  $entities[@entityID = $entityID]

};

declare updating
  %rest:path("/CSD/initSampleDirectory/directory/{$name}/load")
  %rest:GET
  function page:load($name)
{
(
  csd_lsd:load($name)   ,
  csd_webui:redirect_out("CSD/initSampleDirectory")
)
};

declare updating
  %rest:path("/CSD/initSampleDirectory/directory/{$name}/reload")
  %rest:GET
  function page:reload($name)
{
(
  csd_dm:empty($name)   ,
  csd_webui:redirect_out(("CSD/initSampleDirectory/directory/",$name,"/load"))
)

};

declare
  %rest:path("/CSD/initSampleDirectory")
  %rest:GET
  %output:method("xhtml")
  function page:directory_list()
{
let $response :=

Sample Directories

	    {for $name in csd_lsd:sample_directories()
	    order by $name
	    return

	      {$name}

	      {page:services_menu($name)}

	    }

return csd_webui:nocache(  csd_webui:wrapper($response))

};

declare
  %rest:path("/CSD/documents.json")
  %rest:GET
  function page:export_function_details_json(){
  (<rest:response>
    <output:serialization-parameters>
      <output:media-type value='application/json'/>
    </output:serialization-parameters>
  </rest:response>,
  xml-to-json( page:get_export_document_details())
    )
};

declare
  %rest:path("/CSD/documents.xml")
  %rest:GET
  function page:export_document_details_xml(){

    page:get_export_document_details()
};

declare function page:get_export_document_details() {
  <map xmlns="http://www.w3.org/2005/xpath-functions">
    {
      for $name in csd_dm:registered_documents()
      return
      <map key="{string($name)}">
	<string key="careServicesRequest">{csd_webui:generateURL(('CSD/csr/',$name,'/careServicesRequest'))}</string>
	<map key="careServicesRequests">
	  {
	    for $function in (csr_proc:stored_functions(),csr_proc:stored_updating_functions())
	    let $urn:= string($function/@urn)
	    return <string key="{$urn}">{csd_webui:generateURL(('CSD/csr/',$name,'/careServicesRequest/',$urn))}</string>
	  }
	</map>
      </map>
    }
  </map>
};

declare function page:services_menu($name) {

    {if (not(csd_dm:document_source_exists($name))) then

Initialize  {$name}

  else
    (

Get  {$name}
,

Reload {$name}

  )
    }

};


Preparing future : stronger typing in demo apps

svn path=/trunk/eXist-1.0/; revision=4339

xquery version "1.0";

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

import module namespace util="http://exist-db.org/xquery/util";
import module namespace request="http://exist-db.org/xquery/request";
import module namespace session="http://exist-db.org/xquery/session";
import module namespace xdb="http://exist-db.org/xquery/xmldb";
declare namespace system="http://exist-db.org/xquery/system";

declare option exist:serialize "method=xhtml indent=no";

(:~ Points to the location of the xml-highlight.xsl stylesheet stored in the database :)
declare variable $sandbox:XML_HIGHLIGHT_STYLE { "/db/sandbox/xml-highlight.xsl" };

(:~ The required stylesheets were not found in the db. Try to import them. :)
declare function sandbox:import-stylesheets() as xs:string* {
    let $home := system:get-exist-home()
    let $pathSep := util:system-property("file.separator")
    let $dir :=
        	if(ends-with($home, "WEB-INF")) then
        	    concat(substring-before($home, "WEB-INF"), "sandbox", $pathSep, "stylesheets")
        	else
               concat($home, $pathSep, "webapp", $pathSep, "sandbox", $pathSep, "stylesheets")
    let $col := xdb:create-collection("/db", "sandbox")
    return
        concat("Imported: ", xdb:store-files-from-pattern($col, $dir, "*.xsl", "text/xml"))
};

(:~ Check for stylesheets required for the application. Try to import them if they could not be found. :)
declare function sandbox:check-paths() as xs:string* {
    if (not(doc-available($sandbox:XML_HIGHLIGHT_STYLE))) then
        let $dummy := sandbox:import-stylesheets()
        return
            if (not(doc-available($sandbox:XML_HIGHLIGHT_STYLE))) then
                concat($sandbox:XML_HIGHLIGHT_STYLE, " not found! Please store this file into ",
                    "the database collection or the application will not work properly.")
            else ()
    else ()
};

declare function sandbox:init-slots() as element()+ {
    for $i in 1 to 10 return

[{$i}] --- empty ---

};

(:~ Export the current query results into a new document in the database. :)
declare function sandbox:export($docName as xs:string) as element() {
    let $collection := request:get-parameter("collection", ())
    let $wrapper0 := request:get-parameter("wrapper", ())
    let $wrapper := if ($wrapper0) then $wrapper0 else "exist:result"
    let $cached := session:get-attribute("cached")
    return
        if (empty($cached)) then
            <error>No query results to export!</error>
        else
            let $newDoc :=
                element { $wrapper } { $cached }
            return
                util:catch("java.lang.Exception",
                    (let $dummy := xdb:store($collection, $docName, $newDoc, "text/xml") return <ajax-response/>),
                    <error>{$util:exception-message}</error>
                )
};

(:~ Append the given query to the query examples file or update an existing old query. :)
declare function sandbox:save-query($query as xs:string, $description as xs:string) as element() {
    let $root0 := /example-queries
    let $root :=
        if ($root0) then
            $root0
        else
            xdb:store("/db", "examples.xml", <example-queries/>, "text/xml")
    let $existing := $root/query[description = $description][1]
    let $newEntry :=
            <query>
                <description>{$description}</description>
                {$query}
            </query>
    return (
        if ($existing) then
            update replace $existing with $newEntry
        else
            update insert $newEntry into $root,
        <ajax-response/>
    )
};

(:~ Check if the passed query string would correctly compile. :)
declare function sandbox:check-query($query as xs:string) as element() {
    util:declare-option("exist:serialize", "media-type=text/xml omit-xml-declaration=no"),
    <ajax-response>
        { util:compile($query) }
    </ajax-response>
};

(:~ Retrieve a single query result. :)
declare function sandbox:retrieve($num as xs:integer) as element() {
    util:declare-option("exist:serialize", "media-type=text/xml omit-xml-declaration=no indent=no"),
    let $cached := session:get-attribute("cached")
    let $item :=
        <item num="{$num}">
            {$cached[$num]}
        </item>
    return
        transform:transform($item, doc($sandbox:XML_HIGHLIGHT_STYLE), ())
};

(:~ Execute a query :)
declare function sandbox:exec-query($qu as xs:string) as element() {
    let $startTime := util:system-time()
    let $results := util:eval($qu)
    let $elapsed :=
		string(seconds-from-duration(util:system-time() - $startTime))
	let $elapsedStr := concat(substring-before($elapsed, '.'), '.',
			substring(substring-after($elapsed, '.'), 1, 3))
    return (
        session:set-attribute("cached", $results),
        <result hits="{count($results)}" elapsed="{$elapsedStr}"/>
    )
};

declare function sandbox:query($qu as xs:string) as element() {
    util:declare-option("exist:serialize", "media-type=text/xml omit-xml-declaration=no"),
    util:catch("org.exist.xquery.XPathException",
         sandbox:exec-query($qu),
         <error>{$util:exception-message}</error>
    )
 };

declare function sandbox:display-page() as element() {
    util:declare-option("exist:serialize", "media-type=text/html method=xhtml"),

            <title>XQuery Sandbox</title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <link type="text/css" href="styles/sandbox.css" rel="stylesheet"/>


Updated the introspection document to the latest version.

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

declare namespace atom="http://www.w3.org/2005/Atom";
<service xmlns="http://purl.org/atom/app#">
  {
   if (/atom:feed)
   then
   <workspace>
   {
     /atom:feed/atom:title,
     "
",
     let $current := substring-before(base-uri(/atom:feed),'/.feed.atom'),
         $current-path := substring-after($current,'/db')
        for $i in (collection($current)/atom:feed)
           let $path :=  substring-after(substring-before(base-uri($i),'/.feed.atom'),'/db')
              return ( <collection href="/atom/edit{$path}">
                         { $i/atom:title }
                         <accept>text/*,image/*,application/*</accept>
                       </collection>,
                       "
"
                     )
   }
   </workspace>
   else ()
  }
</service>

declare namespace atom="http://www.w3.org/2005/Atom";
<service xmlns="http://purl.org/atom/app#">
  {
   if (/atom:feed)
   then
   <workspace title="{/atom:feed/atom:title}">
   {
     "
",
     let $current := substring-before(base-uri(/atom:feed),'/.feed.atom'),
         $current-path := substring-after($current,'/db')
        for $i in (collection($current)/atom:feed)
           let $path :=  substring-after(substring-before(base-uri($i),'/.feed.atom'),'/db')
              return ( <collection title="{$i/atom:title}" href="/atom/edit{$path}">
                         <accept>text/*,image/*,application/*</accept>
                       </collection>,
                       "
"
                     )
   }
   </workspace>
   else ()
  }
</service>


added recursive addIsPartOf

added recursive addIsPartOf

xquery version "1.0";
module namespace cmdcheck = "http://clarin.eu/cmd/check";
(: checking (trying to ensure) consistency of the IDs in CMD-records (MdSelfLink vs. ResourceProxies vs. IsPartOf)

TODO: check (and/or generate) the inverse links in IsPartOf (vs. ResourceProxies)
:)

(:import module namespace cmd  = "http://clarin.eu/cmd/collections" at "cmd-collections.xqm";:)
import module namespace repo-utils = "http://aac.ac.at/content_repository/utils" at  "/db/cr/repo-utils.xqm";

declare namespace sru = "http://www.loc.gov/zing/srw/";
declare namespace cmd = "http://www.clarin.eu/cmd/";

(:~ default namespace: cmd - declared statically, because dynamic ns-declaration did not work
cmd is the default namespace in (not) all the CMD records
:)
declare default element namespace "http://www.clarin.eu/cmd/";
(:~ default namespace - not declared explicitely, it is declared dynamically where necessary (function: addIsPartOf() :)
declare variable $cmdcheck:default-ns := "http://www.clarin.eu/cmd/";
declare variable $cmdcheck:root-coll := "root";

(:~ init-function meant to call individual functions actually doing something.
at least it resolves x-context to a nodeset
:)
declare function cmdcheck:checks($x-context as xs:string+, $config as node() ) as item()* {

    let $log-file-name := concat('log_checks_', repo-utils:sanitize-name($x-context), '.xml')
    let $log-path := repo-utils:config-value($config, 'log.path')

    let $start-time := util:system-dateTime()

    let $data-collection := repo-utils:context-to-collection($x-context, $config),
        $stat-profiles := cmdcheck:stat-profiles($data-collection),
        $check-linking := cmdcheck:check-linking($data-collection),
        $duration := util:system-dateTime() - $start-time

    let $result-data := <checks context="{$x-context}" on="{$start-time}" duration="{$duration}" >
                    <profiles>{$stat-profiles}</profiles>
                    <check-linking>{$check-linking}</check-linking>
                  </checks>
     let $store := xmldb:store($log-path ,  $log-file-name, $result-data)
    return $store
};

(:~ extracts CMD-Profiles from given nodeset

TODO: profile-name deduction not reliable  - needs match with cmd-terms and diagnostics
:)
declare function cmdcheck:stat-profiles($context as node()*) as item()* {
      (: try- to handle namespace problem - primitively :)
    let $ns-uri := namespace-uri($context[1]/*),
            (: dynamically declare a namespace for the next step, if one is defined in current context
       $dummy := if (exists($ns-uri)) then util:declare-namespace("",$ns-uri) else () :)
       (: this is now trying to overcome the default-ns issue, by accepting with and without ns :)

        $dummy := util:declare-namespace("",xs:anyURI(""))
    let $profiles := util:eval("$context//(MdProfile|cmd:MdProfile)/text()")
    let $distinct-profiles := distinct-values($profiles)
    let $profiles-summary := for $profile in $distinct-profiles
                                let $profile-name := util:eval("$context[.//(MdProfile|cmd:MdProfile)/text() = $profile][1]//(Components|cmd:Components)/*/name()")
                                let $cnt := count($profiles[. eq $profile])
                                return <sru:term>
                                           <sru:value>{$profile}</sru:value>
                                           <sru:numberOfRecords>{$cnt }</sru:numberOfRecords>
                                           <sru:displayTerm>{$profile-name}</sru:displayTerm>
                                         </sru:term>
    let $count-all := count($context)
    return
        <sru:scanResponse xmlns:sru="http://www.loc.gov/zing/srw/" xmlns:fcs="http://clarin.eu/fcs/1.0">
              <sru:version>1.2</sru:version>
              <sru:terms>
                {$profiles-summary }
               </sru:terms>
               <sru:extraResponseData>
                     <fcs:countTerms>{$count-all}</fcs:countTerms>
                 </sru:extraResponseData>
                 <sru:echoedScanRequest>
                      <sru:scanClause>cmd.profile</sru:scanClause>
                  </sru:echoedScanRequest>
           </sru:scanResponse>
};

(:~ checking consistency of the IDs in CMD-records (MdSelfLink vs. ResourceProxies)

this is now solved better (faster) with xpaths in the cmd-testset,
so this is probably obsolete.
it has very bad performance!

TODO: check (and/or generate) the inverse links in IsPartOf (vs. ResourceProxies) :)
declare function cmdcheck:check-linking($context as node()*) as item()* {

let $mdselflinks := $context//MdSelfLink
let $resourceproxies := $context//ResourceProxy
let $resourceproxies-md := $resourceproxies[ResourceType eq 'Metadata']/ResourceRef
(: )let $diff :=  $resourceproxies-md[not(index-of($mdselflinks, self::*))]
let $diff2 :=  $mdselflinks[not($resourceproxies-md = text())]:)
let $diff := for $resource-proxy in $resourceproxies-md
                    let $id := xs:string($resource-proxy/text())
                return if ($mdselflinks[ft:query(.,<term>{$id}</term>)]) then () (: $mdselflinks[ft:query(.,<term>{$id}</term>)] :)
                 else <doc n="{util:document-name($resource-proxy)}" >{$resource-proxy}</doc>

let $diff2 := for $mdselflink in $mdselflinks
                    let $id := xs:string($mdselflink/text())
                return if ($resourceproxies-md[ft:query(.,<term>{$id}</term>)]) then () (: $mdselflinks[ft:query(.,<term>{$id}</term>)] :)
                 else <doc n="{util:document-name($mdselflink)}" >{$mdselflink}</doc>
return ($diff,$diff2)
};

declare function cmdcheck:query-internal($queries, $context as node()+, $result-path as xs:string, $result-filename as xs:string ) as item()* {

    (: collect the xpaths from the before fiddling with the namespace :)
    let $xpaths := $queries//xpath
    (:    let $context := repo-utils:context-to-collection($x-context, $config)
	   $context:= collection("/db/mdrepo-data/cmdi-providers"),	   :)

    let $result-store := xmldb:store($result-path ,  $result-filename, <result test="{$queries//test/xs:string(@id)}" ></result>),
        $result-doc:= doc($result-store)

    let $ns-uri := namespace-uri($context[1]/*)
      (: dynamically declare a default namespace for the xpath-evaluation, if one is defined in current context
      WATCHME: this is not very reliable, mainly meant to handle default-ns: cmd :)
(:      $dummy := if (exists($ns-uri)) then util:declare-namespace("",$ns-uri) else () :)
    let $dummy := util:declare-namespace("",xs:anyURI($ns-uri))

    let $start-time := util:system-dateTime()
    let $upd-dummy :=
        for $xpath in $xpaths
            let $start-time := util:system-dateTime()
            let $answer := util:eval($xpath/text())
            let $duration := util:system-dateTime() - $start-time
           return update insert <xpath key="{$xpath/@key}" label="{$xpath/@label}" dur="{$duration}">{$answer}</xpath> into $result-doc/result

    return $result-doc

};

(:~	WARNING - CHANGES DATA! adds IsPartOf to the CMDrecords (contained in the db-coll)
- expects CMD-records for collections in specific db-coll (with name of the db-coll matching the name of the collectionfile):
    ./_corpusstructure/collection_{db-coll-name}.cmdi
- logs the progress of the processing in a separate file
- can be applied repeatedly - deletes(!) old IsPartOfList, before inserting new

@param $x-context an identifier of a collection (as defined in mappings)
@param $config config-node - used to get log.path and collection-path

TODO: could also generate the CMD-records for collections (assuming db-colls as collections)
      (now done by the python script: dir2cmdicollection.py)
TODO: currently a hack: the collection-records also are marked as root elements - this has to be optional at least,
      and may even be dangerous (count(IsPartOf[@level=1])>1)!
TODO: not recursive yet!
:)
declare function cmdcheck:addIsPartOf-colls($x-context as xs:string, $config as node()*) as item()* {

let $log-file-name := concat('log_addIsPartOf_', $x-context, '.xml')
    let $log-path := repo-utils:config-value($config, 'log.path')
    let $log-doc-path := xmldb:store($log-path ,  $log-file-name, <result></result>)
    let $log-doc := doc($log-doc-path)

    (:let $root-dbcoll := repo-utils:context-to-collection($x-context, $config),:)
    let $root-dbcoll-path := repo-utils:context-to-collection-path($x-context, $config)

    let $coll-dbcoll := '_corpusstructure'

    (: beware empty path!! would return first-level collections and run over whole database :)
    let $colls := if ($root-dbcoll-path ne "") then xmldb:get-child-collections($root-dbcoll-path) else ()
    let $start_time := fn:current-dateTime()

    (: dynamic ns-declaration does not work for xpath
    let $declare-dummy := util:declare-namespace("",xs:anyURI($cmdcheck:default-ns))
    :)
    let $log-dummy := update insert <edit x-context="{$x-context}" root-dbcoll="{$root-dbcoll-path}"
                        coll-dbcoll="{$coll-dbcoll}" count-colls="{count($colls)}" time="{$start_time}" /> into $log-doc/result
    (:if (exists($colls)) then:)
    for $coll_name in $colls[not(.=$coll-dbcoll)]
    (: let $coll_name := 'HomeFamilyManagement' :)
    let $files := collection(concat($root-dbcoll-path,$coll_name))
    (: let $files := xmldb:xcollection($root_coll) :)
	let $coll_file := concat($root-dbcoll-path, $coll-dbcoll, '/collection_', $coll_name, '.cmdi')
	let $coll_doc := doc($coll_file)
	let $coll_id := $coll_doc//MdSelfLink/text()

(:	let $cmdi_files := $files[ends-with(util:document-name(.),".cmdi")]:)

    let $pre_time := util:system-dateTime()
	let $duration := $pre_time - $start_time
 return	( update insert <edit coll="{$coll_name}" collid="{$coll_id}" coll_file="{$coll_file}" count="{count($files)}" time="{$pre_time}" /> into $log-doc/result,
			update delete $files//IsPartOfList,
			update delete $coll_doc//IsPartOfList,
			update insert <IsPartOfList>
								<IsPartOf level="1">{$x-context}</IsPartOf>
								<IsPartOf level="1">{$cmdcheck:root-coll}</IsPartOf>
						  </IsPartOfList>
			  	into $coll_doc//Resources,
			update insert <IsPartOfList>
							<IsPartOf level="2">{$x-context}</IsPartOf>
							<IsPartOf level="1">{$coll_id}</IsPartOf>
						  </IsPartOfList>
				into $files//Resources,
		update value $log-doc/result/edit[last()] with (util:system-dateTime() - $pre_time)
        )
    (:
    return	($coll_name, count($cmdi_files), $coll_file,  update insert <IsPartOfList>
							<IsPartOf level="1">{$coll_id}</IsPartOf>
						  </IsPartOfList> into $cmdi_files//Resources ):)
};

(:~ recursive addIsPartOf
starts by finding "orphaned" mdrecords = expecting that to be the root records.
and continues  ?
:)
declare function cmdcheck:addIsPartOf($x-context as xs:string, $config as node()*) as item()* {

let $log-file-name := concat('log_addIsPartOf_', $x-context, '.xml')
    let $log-path := repo-utils:config-value($config, 'log.path')
    let $log-doc-path := xmldb:store($log-path ,  $log-file-name, <result></result>)
    let $log-doc := doc($log-doc-path)

    let $root-dbcoll := repo-utils:context-to-collection($x-context, $config),
        $root-dbcoll-path := repo-utils:context-to-collection-path($x-context, $config)

(:    let $coll-dbcoll := '_corpusstructure':)

    (: beware empty path!! would return first-level collections and run over whole database :)
    let $colls := if ($root-dbcoll-path ne "") then xmldb:get-child-collections($root-dbcoll-path) else ()
    let $start_time := fn:current-dateTime()

    let $log-dummy := update insert <edit x-context="{$x-context}" root-dbcoll="{$root-dbcoll-path}"
                         count-colls="{count($colls)}" time="{$start_time}" /> into $log-doc/result

    let $root := cmdcheck:addIsPartOf-root($root-dbcoll, $log-doc)
    let $updated := cmdcheck:addIsPartOf-r($root-dbcoll, $root, 1, $log-doc)

    return $log-doc
 };

 (:~ consider those, whose MdSelfLink isn't referenced anywhere (orphans) as the root-cmd-collections
 @returns the edited records :)
 declare function cmdcheck:addIsPartOf-root($context as node()*, $log-doc as node()*) as item()* {

    let $pre_time := util:system-dateTime()

    let $orphaned := $context//CMD[not(Header/MdSelfLink = $context//ResourceProxy[ResourceType eq 'Metadata']/ResourceRef)]

    let $update := ( update insert <edit collid="root" count="{count($orphaned)}" time="{$pre_time}" /> into $log-doc/result,
			update delete $orphaned//IsPartOfList,
			update insert <IsPartOfList>
			                 <IsPartOf>{$cmdcheck:root-coll}</IsPartOf>
						  </IsPartOfList>
				into $orphaned//Resources,
		  update value $log-doc/result/edit[last()] with (util:system-dateTime() - $pre_time)
        )

    return $orphaned

 };

 declare function cmdcheck:addIsPartOf-r($context as node()*, $parents as node()*, $level as xs:integer, $log-doc as node()*) as item()* {

    let $start_time := util:system-dateTime()
    let $log-dummy := update insert <edit level="{$level}"
                        count-colls="{count($parents)}" time="{$start_time}" /> into $log-doc/result

  let $update := for $cmd-record in $parents
                    let $parent-id := $cmd-record//MdSelfLink/text()
                    let $children := $context//CMD[Header/MdSelfLink = $cmd-record//ResourceRef]
                	let $ispartoflist := <IsPartOfList>{($cmd-record//IsPartOfList/IsPartOf[not(text()=$cmdcheck:root-coll)],
                								<IsPartOf >{$parent-id}</IsPartOf>) }
                						  </IsPartOfList>

                    let $pre_time := util:system-dateTime()
                	let $duration := $pre_time - $start_time
                    return	( update insert <edit collid="{$parent-id}" count="{count($children)}" time="{$pre_time}" /> into $log-doc/result,
                			update delete $children//IsPartOfList,
                			update insert $ispartoflist
                				into $children//Resources,
                		  update value $log-doc/result/edit[last()] with (util:system-dateTime() - $pre_time)
                        )

    (: go next level - we dont have to recurse in the update-loop,
     but we can do whole next level in one call :)
    let $next-level := $context//CMD[Header/MdSelfLink = $parents//ResourceRef]
    let $updated := if (exists($next-level)) then  cmdcheck:addIsPartOf-r($context, $next-level ,($level+1),$log-doc)
                        else ()
    return $update
};

xquery version "1.0";
module namespace cmdcheck = "http://clarin.eu/cmd/check";
(: checking (trying to ensure) consistency of the IDs in CMD-records (MdSelfLink vs. ResourceProxies vs. IsPartOf)

TODO: check (and/or generate) the inverse links in IsPartOf (vs. ResourceProxies)
:)

(:import module namespace cmd  = "http://clarin.eu/cmd/collections" at "cmd-collections.xqm";:)
import module namespace repo-utils = "http://aac.ac.at/content_repository/utils" at  "/db/cr/repo-utils.xqm";

declare namespace sru = "http://www.loc.gov/zing/srw/";
declare namespace cmd = "http://www.clarin.eu/cmd/";

(:~ default namespace: cmd - declared statically, because dynamic ns-declaration did not work
cmd is the default namespace in (not) all the CMD records
:)
(:declare default element namespace "http://www.clarin.eu/cmd/";:)
(:~ default namespace - not declared explicitely, it is declared dynamically where necessary (function: addIsPartOf() :)
declare variable $cmdcheck:default-ns := "http://www.clarin.eu/cmd/";

(:~ init-function meant to call individual functions actually doing something.
at least it resolves x-context to a nodeset
:)
declare function cmdcheck:checks($x-context as xs:string+, $config as node() ) as item()* {

    let $log-file-name := concat('log_checks_', repo-utils:sanitize-name($x-context), '.xml')
    let $log-path := repo-utils:config-value($config, 'log.path')

    let $start-time := util:system-dateTime()

    let $data-collection := repo-utils:context-to-collection($x-context, $config),
        $stat-profiles := cmdcheck:stat-profiles($data-collection),
        $check-linking := cmdcheck:check-linking($data-collection),
        $duration := util:system-dateTime() - $start-time

    let $result-data := <checks context="{$x-context}" on="{$start-time}" duration="{$duration}" >
                    <profiles>{$stat-profiles}</profiles>
                    <check-linking>{$check-linking}</check-linking>
                  </checks>
     let $store := xmldb:store($log-path ,  $log-file-name, $result-data)
    return $store
};

(:~ extracts CMD-Profiles from given nodeset

TODO: profile-name deduction not reliable  - needs match with cmd-terms and diagnostics
:)
declare function cmdcheck:stat-profiles($context as node()*) as item()* {
      (: try- to handle namespace problem - primitively :)
    let $ns-uri := namespace-uri($context[1]/*),
            (: dynamically declare a namespace for the next step, if one is defined in current context
       $dummy := if (exists($ns-uri)) then util:declare-namespace("",$ns-uri) else () :)
       (: this is now trying to overcome the default-ns issue, by accepting with and without ns :)

        $dummy := util:declare-namespace("",xs:anyURI(""))
    let $profiles := util:eval("$context//(MdProfile|cmd:MdProfile)/text()")
    let $distinct-profiles := distinct-values($profiles)
    let $profiles-summary := for $profile in $distinct-profiles
                                let $profile-name := util:eval("$context[.//(MdProfile|cmd:MdProfile)/text() = $profile][1]//(Components|cmd:Components)/*/name()")
                                let $cnt := count($profiles[. eq $profile])
                                return <sru:term>
                                           <sru:value>{$profile}</sru:value>
                                           <sru:numberOfRecords>{$cnt }</sru:numberOfRecords>
                                           <sru:displayTerm>{$profile-name}</sru:displayTerm>
                                         </sru:term>
    let $count-all := count($context)
    return
        <sru:scanResponse xmlns:sru="http://www.loc.gov/zing/srw/" xmlns:fcs="http://clarin.eu/fcs/1.0">
              <sru:version>1.2</sru:version>
              <sru:terms>
                {$profiles-summary }
               </sru:terms>
               <sru:extraResponseData>
                     <fcs:countTerms>{$count-all}</fcs:countTerms>
                 </sru:extraResponseData>
                 <sru:echoedScanRequest>
                      <sru:scanClause>cmd.profile</sru:scanClause>
                  </sru:echoedScanRequest>
           </sru:scanResponse>
};

(:~ checking consistency of the IDs in CMD-records (MdSelfLink vs. ResourceProxies)

this is now solved better (faster) with xpaths in the cmd-testset,
so this is probably obsolete.
it has very bad performance!

TODO: check (and/or generate) the inverse links in IsPartOf (vs. ResourceProxies) :)
declare function cmdcheck:check-linking($context as node()*) as item()* {

let $mdselflinks := $context//MdSelfLink
let $resourceproxies := $context//ResourceProxy
let $resourceproxies-md := $resourceproxies[ResourceType eq 'Metadata']/ResourceRef
(: )let $diff :=  $resourceproxies-md[not(index-of($mdselflinks, self::*))]
let $diff2 :=  $mdselflinks[not($resourceproxies-md = text())]:)
let $diff := for $resource-proxy in $resourceproxies-md
                    let $id := xs:string($resource-proxy/text())
                return if ($mdselflinks[ft:query(.,<term>{$id}</term>)]) then () (: $mdselflinks[ft:query(.,<term>{$id}</term>)] :)
                 else <doc n="{util:document-name($resource-proxy)}" >{$resource-proxy}</doc>

let $diff2 := for $mdselflink in $mdselflinks
                    let $id := xs:string($mdselflink/text())
                return if ($resourceproxies-md[ft:query(.,<term>{$id}</term>)]) then () (: $mdselflinks[ft:query(.,<term>{$id}</term>)] :)
                 else <doc n="{util:document-name($mdselflink)}" >{$mdselflink}</doc>
return ($diff,$diff2)
};

declare function cmdcheck:query-internal($queries, $context as node()+, $result-path as xs:string, $result-filename as xs:string ) as item()* {

    (: collect the xpaths from the before fiddling with the namespace :)
    let $xpaths := $queries//xpath
    (:    let $context := repo-utils:context-to-collection($x-context, $config)
	   $context:= collection("/db/mdrepo-data/cmdi-providers"),	   :)

    let $result-store := xmldb:store($result-path ,  $result-filename, <result test="{$queries//test/xs:string(@id)}" ></result>),
        $result-doc:= doc($result-store)

    let $ns-uri := namespace-uri($context[1]/*)
      (: dynamically declare a default namespace for the xpath-evaluation, if one is defined in current context
      WATCHME: this is not very reliable, mainly meant to handle default-ns: cmd :)
(:      $dummy := if (exists($ns-uri)) then util:declare-namespace("",$ns-uri) else () :)
    let $dummy := util:declare-namespace("",xs:anyURI($ns-uri))

    let $start-time := util:system-dateTime()
    let $upd-dummy :=
        for $xpath in $xpaths
            let $start-time := util:system-dateTime()
            let $answer := util:eval($xpath/text())
            let $duration := util:system-dateTime() - $start-time
           return update insert <xpath key="{$xpath/@key}" label="{$xpath/@label}" dur="{$duration}">{$answer}</xpath> into $result-doc/result

    return $result-doc

};

(:~	WARNING - CHANGES DATA! adds IsPartOf to the CMDrecords (contained in the db-coll)
- expects CMD-records for collections in specific db-coll (with name of the db-coll matching the name of the collectionfile):
    ./_corpusstructure/collection_{db-coll-name}.cmdi
- logs the progress of the processing in a separate file
- can be applied repeatedly - deletes(!) old IsPartOfList, before inserting new

@param $x-context an identifier of a collection (as defined in mappings)

TODO: could also generate the CMD-records for collections (assuming db-colls as collections)
      (now done by the python script: dir2cmdicollection.py)
TODO: currently a hack: the collection-records also are marked as root elements - this has to be optional at least,
      and may even be dangerous (count(IsPartOf[@level=1])>1)!
TODO: not recursive yet!
:)
declare function cmdcheck:addIsPartOf($x-context as xs:string, $config as node()*) as item()* {

let $log-file-name := concat('log_addIsPartOf_', $x-context, '.xml')
    let $log-path := repo-utils:config-value($config, 'log.path')
    let $log-doc-path := xmldb:store($log-path ,  $log-file-name, <result></result>)
    let $log-doc := doc($log-doc-path)

    (:let $root-dbcoll := repo-utils:context-to-collection($x-context, $config),:)
    let $root-dbcoll-path := repo-utils:context-to-collection-path($x-context, $config)

    let $coll-dbcoll := '_corpusstructure'

    (: beware empty path!! would return first-level collections and run over whole database :)
    let $colls := if ($root-dbcoll-path ne "") then xmldb:get-child-collections($root-dbcoll-path) else ()
    let $start_time := fn:current-dateTime()

    (: dynamic ns-declaration does not work for xpath
    let $declare-dummy := util:declare-namespace("",xs:anyURI($cmdcheck:default-ns))
    :)
    let $log-dummy := update insert <edit x-context="{$x-context}" root-dbcoll="{$root-dbcoll-path}"
                        coll-dbcoll="{$coll-dbcoll}" count-colls="{count($colls)}" time="{$start_time}" /> into $log-doc/result
    (:if (exists($colls)) then:)
    for $coll_name in $colls[not(.=$coll-dbcoll)]
    (: let $coll_name := 'HomeFamilyManagement' :)
    let $files := collection(concat($root-dbcoll-path,$coll_name))
    (: let $files := xmldb:xcollection($root_coll) :)
	let $coll_file := concat($root-dbcoll-path, $coll-dbcoll, '/collection_', $coll_name, '.cmdi')
	let $coll_doc := doc($coll_file)
	let $coll_id := $coll_doc//MdSelfLink/text()

(:	let $cmdi_files := $files[ends-with(util:document-name(.),".cmdi")]:)

    let $pre_time := util:system-dateTime()
	let $duration := $pre_time - $start_time
 return	( update insert <edit coll="{$coll_name}" collid="{$coll_id}" coll_file="{$coll_file}" count="{count($files)}" time="{$pre_time}" /> into $log-doc/result,
			update delete $files//IsPartOfList,
			update delete $coll_doc//IsPartOfList,
			update insert <IsPartOfList>
								<IsPartOf level="1">{$x-context}</IsPartOf>
								<IsPartOf level="1">root</IsPartOf>
						  </IsPartOfList>
			  	into $coll_doc//Resources,
			update insert <IsPartOfList>
							<IsPartOf level="2">{$x-context}</IsPartOf>
							<IsPartOf level="1">{$coll_id}</IsPartOf>
						  </IsPartOfList>
				into $files//Resources,
		update value $log-doc/result/edit[last()] with (util:system-dateTime() - $pre_time)
        )
    (:
    return	($coll_name, count($cmdi_files), $coll_file,  update insert <IsPartOfList>
							<IsPartOf level="1">{$coll_id}</IsPartOf>
						  </IsPartOfList> into $cmdi_files//Resources ):)
};