minor - renamed variable

minor - renamed variable

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 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 := "html";

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
};

(:~ 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+, $depth as xs:string) as xs:string {
  let $name-prefix := fn:concat($type-name, $depth),
       $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($name-prefix, "-", 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 :)


updated curl request information for test documents

module namespace page = 'http://basex.org/modules/web-page';
import module namespace csd = "urn:ihe:iti:csd:2013" at "../repo/csd_base_library.xqm";
import module namespace csr_proc = "https://github.com/his-interop/openinfoman/csr_proc" at "../repo/csr_processor.xqm";
import module namespace csd_webconf =  "https://github.com/his-interop/openinfoman/csd_webconf" at "../repo/csd_webapp_config.xqm";
import module namespace csd_lsd = "https://github.com/his-interop/openinfoman/csd_lsd" at "../repo/csd_load_sample_directories.xqm";
import module namespace csd_dm = "https://github.com/his-interop/openinfoman/csd_dm" at "../repo/csd_document_manager.xqm";

declare variable $page:test_doc_dirs :=
   ( "../resources/test_docs/"
    ,"../resources-pr/test_docs/"
   );

declare variable $page:test_docs :=
for $test_doc_dir in $page:test_doc_dirs
where file:exists($test_doc_dir)
return file:list($test_doc_dir,boolean('false'),"*.xml");

declare
  %output:method("xhtml")
  %rest:path("/CSD/test/{$name}")
  %rest:GET
function page:show_test_menu($name) {
  page:wrapper(page:test_menu($name))
};

declare
  %rest:path("/CSD/test/{$name}/{$test}")
  %rest:GET
  function page:test($name, $test as xs:string)
{
let $test_doc := page:get_test_doc($test)
return if ($test_doc) then
  csr_proc:process_CSR($test_doc/csd:careServicesRequest,csd_dm:open_document($csd_webconf:db,$name))
else
   (:need better error handling:)

Bad Test Doc

};

declare
  %rest:path("/CSD/test_source/{$test}")
  %rest:GET
  %output:method("xml")
  function page:test_source(
    $test as xs:string)
{
let $test_doc := page:get_test_doc($test)
return if ($test_doc) then
 $test_doc
else

Shame on you

};

declare function page:get_test_doc($test) {
let $files :=
  for $test_doc_dir in $page:test_doc_dirs
  let $dir_base := file:resolve-path($test_doc_dir)
  let $file := file:resolve-path(concat($dir_base , "/" ,$test,".xml"))
  return if ( file:exists($file))  then $file else ()

return if ( count($files) > 0) then
  doc($files[1])
else
  ()
};

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

Registered Documents

  {
    for $name in csd_dm:registered_documents($csd_webconf:db)
    return
Tests for {$name}
{page:test_menu($name)}
  }

Available Stored Functions:

    {for $sf in $csd_webconf:stored_functions return
{text{$sf/@uuid}} implemented by {text{$sf/@method}}() and returns {text{$sf/@content-type}}
}

return page:wrapper($response)
};

declare function page:test_menu($name)
{

  To test submission on your machine you can do:

  curl --data "@test.xml" {$csd_webconf:baseurl}CSD/csr/{$name}/careServicesRequest --header "content-type: text/xml"

  where test.xml is one of the downloaded source documents below

    {for $test_doc in $page:test_docs
    order by $test_doc
    let $test := csd_lsd:fn_base_name($test_doc,".xml")
    return

    {$test}: process on server  /
     download source

    }

};

declare function page:wrapper($response) {

    <link href="{$csd_webconf:baseurl}static/bootstrap/css/bootstrap.css" rel="stylesheet"/>
    <link href="{$csd_webconf:baseurl}static/bootstrap/css/bootstrap-theme.css" rel="stylesheet"/>

module namespace page = 'http://basex.org/modules/web-page';
import module namespace csd = "urn:ihe:iti:csd:2013" at "../repo/csd_base_library.xqm";
import module namespace csr_proc = "https://github.com/his-interop/openinfoman/csr_proc" at "../repo/csr_processor.xqm";
import module namespace csd_webconf =  "https://github.com/his-interop/openinfoman/csd_webconf" at "../repo/csd_webapp_config.xqm";
import module namespace csd_lsd = "https://github.com/his-interop/openinfoman/csd_lsd" at "../repo/csd_load_sample_directories.xqm";
import module namespace csd_dm = "https://github.com/his-interop/openinfoman/csd_dm" at "../repo/csd_document_manager.xqm";

declare variable $page:test_doc_dirs :=
   ( "../resources/test_docs/"
    ,"../resources-pr/test_docs/"
   );

declare variable $page:test_docs :=
for $test_doc_dir in $page:test_doc_dirs
where file:exists($test_doc_dir)
return file:list($test_doc_dir,boolean('false'),"*.xml");

declare
  %output:method("xhtml")
  %rest:path("/CSD/test/{$name}")
  %rest:GET
function page:show_test_menu($name) {
  page:wrapper(page:test_menu($name))
};

declare
  %rest:path("/CSD/test/{$name}/{$test}")
  %rest:GET
  function page:test($name, $test as xs:string)
{
let $test_doc := page:get_test_doc($test)
return if ($test_doc) then
  csr_proc:process_CSR($test_doc/csd:careServicesRequest,csd_dm:open_document($csd_webconf:db,$name))
else
   (:need better error handling:)

Bad Test Doc

};

declare
  %rest:path("/CSD/test_source/{$test}")
  %rest:GET
  %output:method("xml")
  function page:test_source(
    $test as xs:string)
{
let $test_doc := page:get_test_doc($test)
return if ($test_doc) then
 $test_doc
else

Shame on you

};

declare function page:get_test_doc($test) {
let $files :=
  for $test_doc_dir in $page:test_doc_dirs
  let $dir_base := file:resolve-path($test_doc_dir)
  let $file := file:resolve-path(concat($dir_base , "/" ,$test,".xml"))
  return if ( file:exists($file))  then $file else ()

return if ( count($files) > 0) then
  doc($files[1])
else
  ()
};

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

Registered Documents

  {
    for $name in csd_dm:registered_documents($csd_webconf:db)
    return
Tests for {$name}
{page:test_menu($name)}
  }

Available Stored Functions:

    {for $sf in $csd_webconf:stored_functions return
{text{$sf/@uuid}} implemented by {text{$sf/@method}}() and returns {text{$sf/@content-type}}
}

return page:wrapper($response)
};

declare function page:test_menu($name)
{

  To test submission on your machine you can do:

  curl --form "fileupload=@test.xml" {$csd_webconf:baseurl}CSD/csr/{$name}/careServicesRequest

  where test.xml is one of the downloaded source documents below

    {for $test_doc in $page:test_docs
    order by $test_doc
    let $test := csd_lsd:fn_base_name($test_doc,".xml")
    return

    {$test}: process on server  /
     download source

    }

};

declare function page:wrapper($response) {

    <link href="{$csd_webconf:baseurl}static/bootstrap/css/bootstrap.css" rel="stylesheet"/>
    <link href="{$csd_webconf:baseurl}static/bootstrap/css/bootstrap-theme.css" rel="stylesheet"/>


fixup redirect

fixup redirect

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

import module namespace csd_qus = "https://github.com/openhie/openinfoman/csd_qus";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";

declare namespace soap = "http://www.w3.org/2003/05/soap-envelope";

declare variable $page:csd_docs := csd_dm:registered_documents($csd_webconf:db);

declare
  %rest:path("/CSD/getUpdatedServices/{$name}/soap")
  %rest:query-param("mtime", "{$mtime}")
  %rest:GET
  function page:updated_service_soap($name,$mtime)
{
 let $url := csd_webui:generateURL(("CSD/getUpdatedServices/" , $name , "/get"))
 return (
 <rest:response>
   <http:response status="200" >
     <http:header name="Content-Type" value="application/soap+xml"/>
     <http:header name="Content-Disposition"  value="inline; filename=soap_query_updated_services_{$name}.xml"/>
   </http:response>
   </rest:response>
   ,
   csd_qus:create_last_update_request($url,$mtime)
 )

};

declare
  %rest:path("/CSD/getUpdatedServices/{$name}/get")
  %rest:consumes("application/xml", "text/xml", "application/soap+xml")
  %rest:POST("{$updatedServicesRequest}")
  function page:updated_services($name,$updatedServicesRequest)
{
if (csd_dm:document_source_exists($csd_webconf:db,$name)) then
  (
  <rest:response>
    <http:response status="200" >
      <http:header name="Content-Type" value="application/soap+xml"/>
      <http:header name="Content-Disposition"  value="inline; filename=response_query_updated_services_{$name}.xml"/>
    </http:response>
  </rest:response>
  ,
  csd_qus:get_updated_services_soap($updatedServicesRequest/soap:Envelope,csd_dm:open_document($csd_webconf:db,$name))

  )
else
  ()
};

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

Get Updated Services For Sample And Merged Directories

      {
	for $name in $page:csd_docs
	return

Service Directory:{$name}

	  {page:service_menu($name)}

      }

  return page:wrapper($response)
};

declare
  %rest:path("/CSD/getUpdatedServices/{$name}")
  %rest:GET
  %output:method("xhtml")
function page:show_service_menu($name) {
  page:wrapper(
{$name}
{page:service_menu($name)})
};

declare function page:service_menu($name)
{

    Query {$name} for Updated Services by time
    <form method='get' action="/CSD/getUpdatedServices/{$name}/get">
      <input  size="35" id="datetimepicker_{$name}"    name='mtime' type="text" value=""/>
      <input type='submit' />
    </form>

    Get {$name}'s SOAP reuest for Query for Updated Services by time
    <form method='get' action="/CSD/getUpdatedServices/{$name}/soap">
      <input  size="35" id="soap_datetimepicker_{$name}"  name='mtime' type="text" value=""/>
      <input type='submit' />
    </form>

    Submit {$name} SOAP request to:

{csd_webui:generateURL(('CSD/getUpdatedServices/',$name,'/get'))}

};

declare function page:wrapper($response) {
 let $headers := (
    <link rel="stylesheet" type="text/css" media="screen"   href="{csd_webui:generateURL('static/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css')}"/>
    ,

   )
 return csd_webconf:wrapper($response,$headers)
};

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

import module namespace csd_qus = "https://github.com/openhie/openinfoman/csd_qus";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";

declare namespace soap = "http://www.w3.org/2003/05/soap-envelope";

declare variable $page:csd_docs := csd_dm:registered_documents($csd_webconf:db);

declare
  %rest:path("/CSD/getUpdatedServices/{$name}/soap")
  %rest:query-param("mtime", "{$mtime}")
  %rest:GET
  function page:updated_service_soap($name,$mtime)
{
 let $url := csd_webui:generateURL("CSD/getUpdatedServices/" , $name , "/get")
 return (
 <rest:response>
   <http:response status="200" >
     <http:header name="Content-Type" value="application/soap+xml"/>
     <http:header name="Content-Disposition"  value="inline; filename=soap_query_updated_services_{$name}.xml"/>
   </http:response>
   </rest:response>
   ,
   csd_qus:create_last_update_request($url,$mtime)
 )

};

declare
  %rest:path("/CSD/getUpdatedServices/{$name}/get")
  %rest:consumes("application/xml", "text/xml", "application/soap+xml")
  %rest:POST("{$updatedServicesRequest}")
  function page:updated_services($name,$updatedServicesRequest)
{
if (csd_dm:document_source_exists($csd_webconf:db,$name)) then
  (
  <rest:response>
    <http:response status="200" >
      <http:header name="Content-Type" value="application/soap+xml"/>
      <http:header name="Content-Disposition"  value="inline; filename=response_query_updated_services_{$name}.xml"/>
    </http:response>
  </rest:response>
  ,
  csd_qus:get_updated_services_soap($updatedServicesRequest/soap:Envelope,csd_dm:open_document($csd_webconf:db,$name))

  )
else
  ()
};

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

Get Updated Services For Sample And Merged Directories

      {
	for $name in $page:csd_docs
	return

Service Directory:{$name}

	  {page:service_menu($name)}

      }

  return page:wrapper($response)
};

declare
  %rest:path("/CSD/getUpdatedServices/{$name}")
  %rest:GET
  %output:method("xhtml")
function page:show_service_menu($name) {
  page:wrapper(
{$name}
{page:service_menu($name)})
};

declare function page:service_menu($name)
{

    Query {$name} for Updated Services by time
    <form method='get' action="/CSD/getUpdatedServices/{$name}/get">
      <input  size="35" id="datetimepicker_{$name}"    name='mtime' type="text" value=""/>
      <input type='submit' />
    </form>

    Get {$name}'s SOAP reuest for Query for Updated Services by time
    <form method='get' action="/CSD/getUpdatedServices/{$name}/soap">
      <input  size="35" id="soap_datetimepicker_{$name}"  name='mtime' type="text" value=""/>
      <input type='submit' />
    </form>

    Submit {$name} SOAP request to:

{csd_webui:generateURL('CSD/getUpdatedServices/',$name,'/get')}

};

declare function page:wrapper($response) {
 let $headers := (
    <link rel="stylesheet" type="text/css" media="screen"   href="{csd_webui:generateURL('static/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css')}"/>
    ,

   )
 return csd_webconf:wrapper($response,$headers)
};


jsoniq modules uses jsoniq parser

jsoniq modules uses jsoniq parser

jsoniq version "1.0";

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

(:~
 : This module provides the functions defined by the JSONiq specification,
 : sections 1.7 (Functions) and 1.10 (Update Primitives). JSONiq extends
 : the XQuery specification to also deal with JSON data natively. See
 :
 :     http://jsoniq.org/
 :
 : for details.
 :
 : This module depends on having the JSONiq feature enabled in Zorba,
 : i.e., Zorba must be compiled with ZORBA_WITH_JSON.
 :
 : @author Markos Zaharioudakis, Matthias Brantner, Ghislain Fourny
 :)
module namespace jn = "http://jsoniq.org/functions";

import module namespace schema = "http://www.zorba-xquery.com/modules/schema";

declare namespace err = "http://www.w3.org/2005/xqt-errors";
declare namespace jerr = "http://jsoniq.org/errors";
declare namespace js = "http://jsoniq.org/types";

declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
declare option ver:module-version "1.0";

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :   { "prefix" : "Q{http://jsoniq.org/roundtrip}" }
 :
 : @param $items the items to be decoded.
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : The $options parameter contains options for the decoding process.
 : Currently the only supported option is "prefix". It specifies the prefix
 : that determines if this function decodes an item.
 :
 : Example:
 :   jn:decode-from-roundtrip(
 :     { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :     { "prefix" : "pre-" }
 :   )
 : returns the same instance that would be constructed by
 :   { "nan" : xs:double("NaN") }
 :
 : So
 :   let $decoded := jn:decode-from-roundtrip(
 :           { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :           { "prefix" : "pre-" }
 :       )
 :   let $nan := $decoded("nan")
 :   return
 :       ($nan instance of xs:double, $nan)
 : returns
 :   true NaN
 :
 : @param $items the items to be decoded.
 : @param $options the decoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string
 :
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :  {
 :    "prefix" : "Q{http://jsoniq.org/roundtrip}"
 :    "serialization-parameters" : <serialization-parameters xmlns="http://www.w3.org/2010/xslt-xquery-serialization"/>
 :  }
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : @param $items the items to be encoded.
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : Example:
 :   jn:encode-for-roundtrip(
 :     { "nan" : xs:double("NaN") },
 :     { "prefix" : "pre-" }
 :   )
 : returns
 :   { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } }
 :
 : @param $items the items to be encoded.
 : @param $options the encoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string or
          $options("serialization-parameters") is not an element node
 : @error err:XQDY0027 if $options("serialization-parameters") is not a valid
 :        serialization-parameters element
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : Please note that this function allows to parse sequences of whitespace
 : separated objects and arrays.
 :
 : @param $j A string containing a valid JSON text.
 :
 : @return A sequence of JSON Object or Array item.
 :
 : @error jerr:JNDY0021 if the given string is not valid JSON.
 :)
declare function jn:parse-json($j as xs:string?) as json-item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : @param $j A string containing a valid JSON text.
 : @param $o A JSON object defining options to configure the parser.
 : Allowed options are
 :

 :
jsoniq-multiple-top-level-items: allow parsing of sequences of JSON Objects and Arrays (boolean; default: true)

 :
jsoniq-strip-top-level-array: if the top-level JSON item is an array, strip it and return its elements as multiple top-level items (boolean; default: false)

 :

 :
 : @error jerr:JNDY0021 if the given string is not valid JSON or
 :   if jsoniq-multiple-top-level-items is false and there is additional
 :   content after the first JSON Object or Array.
 : @error jerr:JNTY0020 if the value for the option
 :   jsoniq-multiple-top-level-items is not of type xs:boolean.
 :
 : @return a sequence of JSON Object or Array item.
 :)
declare function jn:parse-json(
  $j as xs:string?,
  $o as object()) as json-item()* external;

(:~
 : Returns the names used in the object.
 : The names will be returned in an implementation-defined order
 :
 : @param $o A JSON Object.
 : @return The names of pairs in the object.
 :)
declare function jn:keys($o as object()) as xs:string* external;

(:~
 : Returns the value of a JSON Pair with a given name within a given JSON object.
 : If no such pair exists in the object, returns the empty sequence.
 :
 : @param $o A JSON Object.
 : @param $name The name of the pair whose value is to be retrieved
 : @return the value of specified pair within the given object, or the empty sequence.
 :)
(: obsolete - use $o($name) instead :)
declare function jn:value($o as object(), $name as xs:string) as item()? external;

(:~
 : Returns the size of a JSON Array. The size of an Array is
 : the number of members contained within it.
 :
 : @param $j A JSON Array.
 : @return The number of items in $j.
 :)
declare function jn:size($j as array()) as xs:integer external;

(:~
 : Returns the member of an Array at the specified position (starting from 1).
 : If the position is out of bounds of the array, returns the empty sequence.
 :
 : @param $a A JSON Array.
 : @param $p The position in the array.
 : @return The member at the specified position, or empty sequence.
 :)
(: obsolete - use $a($p) instead :)
declare function jn:member($a as array(), $p as xs:integer) as item()? external;

(:~
 : Creates an object from the specified pairs of another given object.
 : Specifically, for each name in $names, if the object $o has a pair with
 : that name, then a copy of that pair is included in the new object.
 :
 : @param $o A JSON Object.
 : @param $names The names of the pairs to copy out of $o and insert into the new object
 : @return The new object.
 :)
declare function jn:project($o as object(), $names as xs:string*) as object() external;

(:~
 : Returns the members of an Array.
 :
 : @param $a A JSON Array.
 : @return The members of the specified array.
 :)
declare function jn:members($o as array()) as item()* external;

(:~
 : Recursively "flatten" a JSON Array, by replacing any arrays with their
 : members. Equivalent to
 :
 :   define function jn:flatten($arg as array()) {
 :     for $value in jn:values($arg)
 :     return
 :       if ($value instance of array())
 :       then jn:flatten($value)
 :       else $value
 :   };
 :
 : @param $a A JSON Array.
 : @return The flattened version of $a.
 :)
declare function jn:flatten($a as array()) as item()* external;

(:~
 : This function allows dynamic object construction by merging all
 : its object parameters into a single object with a so-called "simple
 : object union". A simple object union creates a new object, the pairs
 : property of which is obtained by accumulating the pairs of all operand
 : objects. An error jerr:JNDY0003 is raised if two pairs with the same
 : name are encountered.
 :
 : @param $o A sequence of objects.
 :
 : @return The simple object union.
 :
 : @error jerr:JNDY0003 if there is a pair collision.
 :)
declare function jn:object($o as object()*) as object() external;

(:~
 : Returns the JSON null.
 :
 : @return The JSON null.
 :)
declare function jn:null() as js:null external;

(:~
 : Tests whether the supplied atomic item is a JSON null.
 :
 : @param An atomic item.
 :
 : @return true if the item is of type js:null.
 :)
declare function jn:is-null($i as xs:anyAtomicType) as xs:boolean external;

xquery version "1.0";

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

(:~
 : This module provides the functions defined by the JSONiq specification,
 : sections 1.7 (Functions) and 1.10 (Update Primitives). JSONiq extends
 : the XQuery specification to also deal with JSON data natively. See
 :
 :     http://jsoniq.org/
 :
 : for details.
 :
 : This module depends on having the JSONiq feature enabled in Zorba,
 : i.e., Zorba must be compiled with ZORBA_WITH_JSON.
 :
 : @author Markos Zaharioudakis, Matthias Brantner, Ghislain Fourny
 :)
module namespace jn = "http://jsoniq.org/functions";

import module namespace schema = "http://www.zorba-xquery.com/modules/schema";

declare namespace err = "http://www.w3.org/2005/xqt-errors";
declare namespace jerr = "http://jsoniq.org/errors";
declare namespace js = "http://jsoniq.org/types";

declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
declare option ver:module-version "1.0";

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :   { "prefix" : "Q{http://jsoniq.org/roundtrip}" }
 :
 : @param $items the items to be decoded.
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : The $options parameter contains options for the decoding process.
 : Currently the only supported option is "prefix". It specifies the prefix
 : that determines if this function decodes an item.
 :
 : Example:
 :   jn:decode-from-roundtrip(
 :     { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :     { "prefix" : "pre-" }
 :   )
 : returns the same instance that would be constructed by
 :   { "nan" : xs:double("NaN") }
 :
 : So
 :   let $decoded := jn:decode-from-roundtrip(
 :           { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :           { "prefix" : "pre-" }
 :       )
 :   let $nan := $decoded("nan")
 :   return
 :       ($nan instance of xs:double, $nan)
 : returns
 :   true NaN
 :
 : @param $items the items to be decoded.
 : @param $options the decoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string
 :
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :  {
 :    "prefix" : "Q{http://jsoniq.org/roundtrip}"
 :    "serialization-parameters" : <serialization-parameters xmlns="http://www.w3.org/2010/xslt-xquery-serialization"/>
 :  }
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : @param $items the items to be encoded.
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : Example:
 :   jn:encode-for-roundtrip(
 :     { "nan" : xs:double("NaN") },
 :     { "prefix" : "pre-" }
 :   )
 : returns
 :   { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } }
 :
 : @param $items the items to be encoded.
 : @param $options the encoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string or
          $options("serialization-parameters") is not an element node
 : @error err:XQDY0027 if $options("serialization-parameters") is not a valid
 :        serialization-parameters element
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : Please note that this function allows to parse sequences of whitespace
 : separated objects and arrays.
 :
 : @param $j A string containing a valid JSON text.
 :
 : @return A sequence of JSON Object or Array item.
 :
 : @error jerr:JNDY0021 if the given string is not valid JSON.
 :)
declare function jn:parse-json($j as xs:string?) as json-item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : @param $j A string containing a valid JSON text.
 : @param $o A JSON object defining options to configure the parser.
 : Allowed options are
 :

 :
jsoniq-multiple-top-level-items: allow parsing of sequences of JSON Objects and Arrays (boolean; default: true)

 :
jsoniq-strip-top-level-array: if the top-level JSON item is an array, strip it and return its elements as multiple top-level items (boolean; default: false)

 :

 :
 : @error jerr:JNDY0021 if the given string is not valid JSON or
 :   if jsoniq-multiple-top-level-items is false and there is additional
 :   content after the first JSON Object or Array.
 : @error jerr:JNTY0020 if the value for the option
 :   jsoniq-multiple-top-level-items is not of type xs:boolean.
 :
 : @return a sequence of JSON Object or Array item.
 :)
declare function jn:parse-json(
  $j as xs:string?,
  $o as object()) as json-item()* external;

(:~
 : Returns the names used in the object.
 : The names will be returned in an implementation-defined order
 :
 : @param $o A JSON Object.
 : @return The names of pairs in the object.
 :)
declare function jn:keys($o as object()) as xs:string* external;

(:~
 : Returns the value of a JSON Pair with a given name within a given JSON object.
 : If no such pair exists in the object, returns the empty sequence.
 :
 : @param $o A JSON Object.
 : @param $name The name of the pair whose value is to be retrieved
 : @return the value of specified pair within the given object, or the empty sequence.
 :)
(: obsolete - use $o($name) instead :)
declare function jn:value($o as object(), $name as xs:string) as item()? external;

(:~
 : Returns the size of a JSON Array. The size of an Array is
 : the number of members contained within it.
 :
 : @param $j A JSON Array.
 : @return The number of items in $j.
 :)
declare function jn:size($j as array()) as xs:integer external;

(:~
 : Returns the member of an Array at the specified position (starting from 1).
 : If the position is out of bounds of the array, returns the empty sequence.
 :
 : @param $a A JSON Array.
 : @param $p The position in the array.
 : @return The member at the specified position, or empty sequence.
 :)
(: obsolete - use $a($p) instead :)
declare function jn:member($a as array(), $p as xs:integer) as item()? external;

(:~
 : Creates an object from the specified pairs of another given object.
 : Specifically, for each name in $names, if the object $o has a pair with
 : that name, then a copy of that pair is included in the new object.
 :
 : @param $o A JSON Object.
 : @param $names The names of the pairs to copy out of $o and insert into the new object
 : @return The new object.
 :)
declare function jn:project($o as object(), $names as xs:string*) as object() external;

(:~
 : Returns the members of an Array.
 :
 : @param $a A JSON Array.
 : @return The members of the specified array.
 :)
declare function jn:members($o as array()) as item()* external;

(:~
 : Recursively "flatten" a JSON Array, by replacing any arrays with their
 : members. Equivalent to
 :
 :   define function jn:flatten($arg as array()) {
 :     for $value in jn:values($arg)
 :     return
 :       if ($value instance of array())
 :       then jn:flatten($value)
 :       else $value
 :   };
 :
 : @param $a A JSON Array.
 : @return The flattened version of $a.
 :)
declare function jn:flatten($a as array()) as item()* external;

(:~
 : This function allows dynamic object construction by merging all
 : its object parameters into a single object with a so-called "simple
 : object union". A simple object union creates a new object, the pairs
 : property of which is obtained by accumulating the pairs of all operand
 : objects. An error jerr:JNDY0003 is raised if two pairs with the same
 : name are encountered.
 :
 : @param $o A sequence of objects.
 :
 : @return The simple object union.
 :
 : @error jerr:JNDY0003 if there is a pair collision.
 :)
declare function jn:object($o as object()*) as object() external;

(:~
 : Returns the JSON null.
 :
 : @return The JSON null.
 :)
declare function jn:null() as js:null external;

(:~
 : Tests whether the supplied atomic item is a JSON null.
 :
 : @param An atomic item.
 :
 : @return true if the item is of type js:null.
 :)
declare function jn:is-null($i as xs:anyAtomicType) as xs:boolean external;


junk the email field

junk the email field

module namespace anonymize = "https://github.com/openhie/openinfoman-anon";
import module namespace functx = "http://www.functx.com";

declare namespace csd  =  "urn:ihe:iti:csd:2013";

declare variable $anonymize:exclude_address := (
  'street',  'st',  'way',  'road',  'hwy',  'highway' , 'lane','ave','avenue', 'rd', 's', 'n', 'e','w','sw','nw','se','ne'
);

declare variable $anonymize:exclude_name := (
  'clinic','hospital','hosp','facility','health','primary','district','regional','referal','center','centre'
);

declare function anonymize:document2($src_doc,$provider_values,$organization_values,$facility_values) {
  $src_doc
};
declare function anonymize:document($src_doc,$provider_values,$organization_values,$facility_values) {
   <csd:CSD>
     <csd:organizationDirectory>
       {
	 for $org in $src_doc/csd:CSD/csd:organizationDirectory/csd:organization
	 return anonymize:organization($org,$organization_values)
       }
     </csd:organizationDirectory>
     <csd:facilityDirectory>
       {
	 for $fac in $src_doc/csd:CSD/csd:facilityDirectory/csd:facility
	 return anonymize:facility($fac,$facility_values)
       }
     </csd:facilityDirectory>
     <csd:serviceDirectory>{$src_doc/csd:CSD/csd:serviceDirectory/csd:service}</csd:serviceDirectory>
     <csd:providerDirectory>
       {
	 for $provider in $src_doc/csd:CSD/csd:providerDirectory/csd:provider
	 return anonymize:provider($provider,$provider_values,$facility_values)
       }
     </csd:providerDirectory>
   </csd:CSD>
};

declare function anonymize:scramble($source) {
  let $tokens := functx:chars($source)
  let $all :=
      for $p in (1 to count($tokens))
      let $t := $tokens[$p]
      return
	 if (matches($t,'\d'))
	 then string(random:integer(max((0,9)))+1)
	 else $t
  return string-join($all,'')

};

declare function anonymize:replace-word($source,$values) {
  anonymize:replace-word($source,$values,map {})
};

declare function anonymize:replace-word($source,$values,$map) {
  anonymize:replace-word($source,$values,$map,())
};

declare function anonymize:replace-word($source,$values,$map,$excludes) {
  let $mapped := map:get($map,$source)
  return
    if ($mapped)
    then $mapped
    else if ($excludes = lower-case($source) )
    then $source
    else if (matches($source,"\d"))
    then anonymize:scramble($source)
    else
      let $rand := random:integer(count($values)) + 1
      return $values[$rand]
};

declare function anonymize:replace-string($source,$values){
  anonymize:replace-string($source,$values,map {})
};

declare function anonymize:replace-string($source,$values,$map) {
  anonymize:replace-string($source,$values,$map,())
};

declare function anonymize:replace-string($source,$values,$map,$excludes) {
  (:tokenize the $source text on non-letters, replace with value and join:)
  let $tokens := tokenize($source,'\W+')
  let $joins := tokenize($source,'\w+')
  let $anons :=
    for $t in $tokens
    return anonymize:replace-word($t,$values,$map,$excludes)
  let $count := max((count($anons), count($joins)))
  let $all :=
    if (matches($source,'^\W+'))
    then
      for $p in (0 to $count)
      return ($anons[$p],$joins[$p])
    else
      for $p in (0 to $count)
      return ($joins[$p],$anons[$p])
  return string-join($all)

};

declare function  anonymize:organization($organization,$values) {
  anonymize:organization($organization,$values,map{})
};

declare function  anonymize:organization($organization,$values,$map) {
  copy $org  := $organization
  modify (
    let $anon_name := anonymize:replace-string($org/csd:primaryName,$values,$map ,$anonymize:exclude_name)
    return replace value of node $org/csd:primaryName with $anon_name
    ,
    for $cp in $org/csd:contactPoint
    let $anon_cp :=
      if (string($cp/@code) = 'EMAIL')
      then
        <csd:contactPoint>
          <csd:codedType code="{$cp/csd:codedType/@code}" codingScheme="{$cp/csd:codedType/@codingScheme}">someone@nowhere.com</csd:codedType>
	</csd:contactPoint>
      else
        <csd:contactPoint>
          <csd:codedType code="{$cp/csd:codedType/@code}" codingScheme="{$cp/csd:codedType/@codingScheme}">{anonymize:scramble($cp/csd:codedType/text())}</csd:codedType>
	</csd:contactPoint>
    return replace node $cp with $anon_cp
    ,
    for $addr in $org/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$values,$map, $anonymize:exclude_address)
      return  replace value of node $line with $anon_addr
    ,
    for $contact_name in $org/csd:contact/csd:person/csd:name
    let $anon_name := anonymize:provider-name($contact_name,$values)
    return replace node $contact_name with $anon_name
    ,
    for $addr in $org/csd:contact/csd:person/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$values,$map, $anonymize:exclude_address)
      return replace value of node $line with $anon_addr

  )
  return $org
};

declare function  anonymize:facility($facility,$values) {
  anonymize:facility($facility,$values,map {})
};

declare function  anonymize:facility($facility,$values,$map) {
  copy $fac  := $facility
  modify (
    let $anon_name := anonymize:replace-string($fac/csd:primaryName,$values,$map,$anonymize:exclude_name)
    return replace value of node $fac/csd:primaryName with $anon_name
    ,
    for $cp in $fac/csd:contactPoint
    let $anon_cp :=
      <csd:contactPoint>
        <csd:codedType code="{$cp/csd:codedType/@code}" codingScheme="{$cp/csd:codedType/@codingScheme}">{anonymize:scramble($cp/csd:codedType/text())}</csd:codedType>
      </csd:contactPoint>
    return replace node $cp with $anon_cp
    ,
    for $addr in $fac/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or  @component = 'city']
      let $anon_addr :=  anonymize:replace-string($line/text(),$values,$map,$anonymize:exclude_address)
      return replace value of node $line with $anon_addr
    ,
    for $contact_name in $fac/csd:contact/csd:person/csd:name
    let $anon_name := anonymize:provider-name($contact_name,$values)
    return replace node $contact_name with $anon_name
    ,
    for $addr in $fac/csd:contact/csd:person/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or  @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$values,$map, $anonymize:exclude_address)
      return replace value of node $line with $anon_addr

  )
  return $fac
};

declare function anonymize:provider($provider,$values,$addr_values) {
  anonymize:provider($provider,$values,$addr_values,map {})
};

declare function anonymize:provider($provider,$values,$addr_values,$map) {
  copy $prov := $provider
  modify (
    for $name in $prov/csd:demographic/csd:name
    let $anon_name := anonymize:provider-name($name,$values)
    return replace node $name with $anon_name
    ,
    for $cp in $prov/csd:demographic/csd:contactPoint
      let $anon_cp :=
      <csd:contactPoint>
        <csd:codedType code="{$cp/csd:codedType/@code}" codingScheme="{$cp/csd:codedType/@codingScheme}">{anonymize:scramble($cp/csd:codedType/text())}</csd:codedType>
      </csd:contactPoint>
      return replace node $cp with $anon_cp
    ,
    for $addr in $prov/csd:demographic/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$addr_values,$map, $anonymize:exclude_address)
      return  replace value of node $line with $anon_addr

    )
  return $prov

};

declare function anonymize:provider-name($name,$values) {
(: Example Input:
				<name>
					<commonName>Banargee, Dev</commonName>
					<honorific>Dr.</honorific>
					<forename>Dev</forename>
					<surname>Banerjee</surname>
				</name>
:)
    let $honor :=  ($name/csd:honorific)[1]/text()
    let $sur :=  ($name/csd:surname)[1]/text()
    let $fore :=  ($name/csd:foreame)[1]/text()
    let $common :=  ($name/csd:commonName)[1]/text()
    let $anon_sur := anonymize:replace-string($sur,$values)
    let $anon_fore := anonymize:replace-string($fore,$values)

    let $map_0 :=
      if ($honor)
      then map {$honor: $honor}
      else map {}
    let $map_1 :=
      if ($anon_sur)
      then map:put($map_0,$sur,$anon_sur)
      else $map_0
    let $map_2 :=
      if ($anon_fore)
      then map:put($map_0,$fore,$anon_fore)
      else $map_1

    let $anon_common := anonymize:replace-string($common,$values,$map_2)
    let $anon_name :=
      <csd:name>
         <csd:commonName>{$anon_common}</csd:commonName>
	 {if ($honor) then <csd:honorific>{$honor}</csd:honorific> else () }
	 {if ($anon_fore) then	 <csd:forename>{$anon_fore}</csd:forename> else () }
	 {if ($anon_sur) then  <csd:surname>{$anon_sur}</csd:surname> else () }
      </csd:name>
    return $anon_name
};

module namespace anonymize = "https://github.com/openhie/openinfoman-anon";
import module namespace functx = "http://www.functx.com";

declare namespace csd  =  "urn:ihe:iti:csd:2013";

declare variable $anonymize:exclude_address := (
  'street',  'st',  'way',  'road',  'hwy',  'highway' , 'lane','ave','avenue', 'rd', 's', 'n', 'e','w','sw','nw','se','ne'
);

declare variable $anonymize:exclude_name := (
  'clinic','hospital','hosp','facility','health','primary','district','regional','referal','center','centre'
);

declare function anonymize:document2($src_doc,$provider_values,$organization_values,$facility_values) {
  $src_doc
};
declare function anonymize:document($src_doc,$provider_values,$organization_values,$facility_values) {
   <csd:CSD>
     <csd:organizationDirectory>
       {
	 for $org in $src_doc/csd:CSD/csd:organizationDirectory/csd:organization
	 return anonymize:organization($org,$organization_values)
       }
     </csd:organizationDirectory>
     <csd:facilityDirectory>
       {
	 for $fac in $src_doc/csd:CSD/csd:facilityDirectory/csd:facility
	 return anonymize:facility($fac,$facility_values)
       }
     </csd:facilityDirectory>
     <csd:serviceDirectory>{$src_doc/csd:CSD/csd:serviceDirectory/csd:service}</csd:serviceDirectory>
     <csd:providerDirectory>
       {
	 for $provider in $src_doc/csd:CSD/csd:providerDirectory/csd:provider
	 return anonymize:provider($provider,$provider_values,$facility_values)
       }
     </csd:providerDirectory>
   </csd:CSD>
};

declare function anonymize:scramble($source) {
  let $tokens := functx:chars($source)
  let $all :=
      for $p in (1 to count($tokens))
      let $t := $tokens[$p]
      return
	 if (matches($t,'\d'))
	 then string(random:integer(max((0,9)))+1)
	 else $t
  return string-join($all,'')

};

declare function anonymize:replace-word($source,$values) {
  anonymize:replace-word($source,$values,map {})
};

declare function anonymize:replace-word($source,$values,$map) {
  anonymize:replace-word($source,$values,$map,())
};

declare function anonymize:replace-word($source,$values,$map,$excludes) {
  let $mapped := map:get($map,$source)
  return
    if ($mapped)
    then $mapped
    else if ($excludes = lower-case($source) )
    then $source
    else if (matches($source,"\d"))
    then anonymize:scramble($source)
    else
      let $rand := random:integer(count($values)) + 1
      return $values[$rand]
};

declare function anonymize:replace-string($source,$values){
  anonymize:replace-string($source,$values,map {})
};

declare function anonymize:replace-string($source,$values,$map) {
  anonymize:replace-string($source,$values,$map,())
};

declare function anonymize:replace-string($source,$values,$map,$excludes) {
  (:tokenize the $source text on non-letters, replace with value and join:)
  let $tokens := tokenize($source,'\W+')
  let $joins := tokenize($source,'\w+')
  let $anons :=
    for $t in $tokens
    return anonymize:replace-word($t,$values,$map,$excludes)
  let $count := max((count($anons), count($joins)))
  let $all :=
    if (matches($source,'^\W+'))
    then
      for $p in (0 to $count)
      return ($anons[$p],$joins[$p])
    else
      for $p in (0 to $count)
      return ($joins[$p],$anons[$p])
  return string-join($all)

};

declare function  anonymize:organization($organization,$values) {
  anonymize:organization($organization,$values,map{})
};

declare function  anonymize:organization($organization,$values,$map) {
  copy $org  := $organization
  modify (
    let $anon_name := anonymize:replace-string($org/csd:primaryName,$values,$map ,$anonymize:exclude_name)
    return replace value of node $org/csd:primaryName with $anon_name
    ,
    for $cp in $org/csd:contactPoint
    let $anon_cp :=
      <csd:contactPoint>
        <csd:codedType code="{$cp/csd:codedType/@code}" codingScheme="{$cp/csd:codedType/@codingScheme}">{anonymize:scramble($cp/csd:codedType/text())}</csd:codedType>
      </csd:contactPoint>
    return replace node $cp with $anon_cp
    ,
    for $addr in $org/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$values,$map, $anonymize:exclude_address)
      return  replace value of node $line with $anon_addr
    ,
    for $contact_name in $org/csd:contact/csd:person/csd:name
    let $anon_name := anonymize:provider-name($contact_name,$values)
    return replace node $contact_name with $anon_name
    ,
    for $addr in $org/csd:contact/csd:person/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$values,$map, $anonymize:exclude_address)
      return replace value of node $line with $anon_addr

  )
  return $org
};

declare function  anonymize:facility($facility,$values) {
  anonymize:facility($facility,$values,map {})
};

declare function  anonymize:facility($facility,$values,$map) {
  copy $fac  := $facility
  modify (
    let $anon_name := anonymize:replace-string($fac/csd:primaryName,$values,$map,$anonymize:exclude_name)
    return replace value of node $fac/csd:primaryName with $anon_name
    ,
    for $cp in $fac/csd:contactPoint
    let $anon_cp :=
      <csd:contactPoint>
        <csd:codedType code="{$cp/csd:codedType/@code}" codingScheme="{$cp/csd:codedType/@codingScheme}">{anonymize:scramble($cp/csd:codedType/text())}</csd:codedType>
      </csd:contactPoint>
    return replace node $cp with $anon_cp
    ,
    for $addr in $fac/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or  @component = 'city']
      let $anon_addr :=  anonymize:replace-string($line/text(),$values,$map,$anonymize:exclude_address)
      return replace value of node $line with $anon_addr
    ,
    for $contact_name in $fac/csd:contact/csd:person/csd:name
    let $anon_name := anonymize:provider-name($contact_name,$values)
    return replace node $contact_name with $anon_name
    ,
    for $addr in $fac/csd:contact/csd:person/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or  @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$values,$map, $anonymize:exclude_address)
      return replace value of node $line with $anon_addr

  )
  return $fac
};

declare function anonymize:provider($provider,$values,$addr_values) {
  anonymize:provider($provider,$values,$addr_values,map {})
};

declare function anonymize:provider($provider,$values,$addr_values,$map) {
  copy $prov := $provider
  modify (
    for $name in $prov/csd:demographic/csd:name
    let $anon_name := anonymize:provider-name($name,$values)
    return replace node $name with $anon_name
    ,
    for $cp in $prov/csd:demographic/csd:contactPoint
      let $anon_cp :=
      <csd:contactPoint>
        <csd:codedType code="{$cp/csd:codedType/@code}" codingScheme="{$cp/csd:codedType/@codingScheme}">{anonymize:scramble($cp/csd:codedType/text())}</csd:codedType>
      </csd:contactPoint>
      return replace node $cp with $anon_cp
    ,
    for $addr in $prov/csd:demographic/csd:address
      for $line in $addr/csd:addressLine[@component = 'streetAddress' or @component = 'StreetAddress' or @component = 'city']
      let $anon_addr := anonymize:replace-string($line/text(),$addr_values,$map, $anonymize:exclude_address)
      return  replace value of node $line with $anon_addr

    )
  return $prov

};

declare function anonymize:provider-name($name,$values) {
(: Example Input:
				<name>
					<commonName>Banargee, Dev</commonName>
					<honorific>Dr.</honorific>
					<forename>Dev</forename>
					<surname>Banerjee</surname>
				</name>
:)
    let $honor :=  ($name/csd:honorific)[1]/text()
    let $sur :=  ($name/csd:surname)[1]/text()
    let $fore :=  ($name/csd:foreame)[1]/text()
    let $common :=  ($name/csd:commonName)[1]/text()
    let $anon_sur := anonymize:replace-string($sur,$values)
    let $anon_fore := anonymize:replace-string($fore,$values)

    let $map_0 :=
      if ($honor)
      then map {$honor: $honor}
      else map {}
    let $map_1 :=
      if ($anon_sur)
      then map:put($map_0,$sur,$anon_sur)
      else $map_0
    let $map_2 :=
      if ($anon_fore)
      then map:put($map_0,$fore,$anon_fore)
      else $map_1

    let $anon_common := anonymize:replace-string($common,$values,$map_2)
    let $anon_name :=
      <csd:name>
         <csd:commonName>{$anon_common}</csd:commonName>
	 {if ($honor) then <csd:honorific>{$honor}</csd:honorific> else () }
	 {if ($anon_fore) then	 <csd:forename>{$anon_fore}</csd:forename> else () }
	 {if ($anon_sur) then  <csd:surname>{$anon_sur}</csd:surname> else () }
      </csd:name>
    return $anon_name
};


[ignore] removed typo

[ignore] removed typo

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

xquery version "1.0";
(: $Id$ :)
(:
    Module: examples setup
:)

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

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

declare function setup:main() as element()
{

Examples Setup

        {
let $action := request:get-parameter("action", ()) return
		if($action) then
		                (
		                    if($action eq "Import Example Data") then
		                    (
		                        setup:importLocal()
		                    )
		                    else if($action eq "Import Files") then
		                    (
		                        setup:importFromURLs()
		                    )
		                    else
		                    (
		                        setup:report()
		                    )
		                )
		                else
		                (
		                    setup:select()
		                )

        }

};

declare function setup:importLocal() as element()+
{
    let $home := system:get-exist-home(),
    $pathSep := util:system-property("file.separator"),
    $dir := if (doc-available(concat("file:///", $home, "/exist-samples/examples.xml"))) then
        (
            concat($home, $pathSep, "exist-samples")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            concat(substring-before($home, "WEB-INF"), "samples")
        )
        else
        (
            concat($home, $pathSep, "samples")
        ),
    $webapp := if (doc-available(concat("file:///", $home, "/webapp/index.xml"))) then
        (
            concat($home, $pathSep, "webapp")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            substring-before($home, "WEB-INF")
        )
        else
        (
            concat($home, $pathSep, "webapp")
        )
    return (
                setup:create-collection("/db/system/config", "db"),
                setup:create-collection("/db/system/config/db", "shakespeare"),
                setup:store-files("/db/system/config/db/shakespeare", $dir,
                    "shakespeare/collection.xconf", "text/xml"),
                setup:create-collection("/db", "shakespeare"),
                setup:create-collection("/db/shakespeare", "plays"),
                setup:store-files("/db/shakespeare/plays", $dir,  "shakespeare/*.xml", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.xsl", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.css", "text/css"),
                setup:create-collection("/db", "xinclude"),
                setup:create-collection("/db/xinclude", "styles"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xsl", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xml", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xq", "application/xquery"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.jpg", "image/jpeg"),
                setup:store-files("/db/xinclude/styles", $dir, "xinclude/styles/*", "text/css"),
                setup:create-collection("/db/xinclude", "scripts"),
                setup:create-collection("/db/xinclude/scripts", "syntax"),
                setup:store-files("/db/xinclude/scripts/syntax", $dir, "xinclude/scripts/syntax/*.js", "application/x-javascript"),
                setup:create-collection("/db", "library"),
                setup:store-files("/db/library", $dir, "*.rdf", "text/xml"),
                setup:create-collection("/db", "mods"),
                setup:store-files("/db/mods", $dir, "mods/*.xml", "text/xml"),
                setup:store-files("/db", $dir, "*.xml", "text/xml"),
                setup:create-collection("/db/system/config/db", "mondial"),
                setup:store-files("/db/system/config/db/mondial", $dir, "mondial.xconf", "text/xml"),
                setup:create-collection("/db", "xproc"),
                setup:create-collection("/db/xproc", "unit-test"),
                setup:create-collection("/db/xproc", "xml"),
                setup:create-collection("/db/xproc", "xslt"),
                setup:create-collection("/db/xproc", "result"),
                setup:create-collection("/db/xproc", "examples"),
                setup:create-collection("/db/xproc", "pipelines"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xml", "text/xml"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xql", "application/xquery"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/pipelines", $webapp, "xproc/pipelines/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xml", $webapp, "xproc/xml/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xslt", $webapp, "xproc/xml/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xproc", "text/xml"),
                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xml", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xql", "application/xquery"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xml", "text/xml"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xql", "application/xquery"),

                setup:create-collection("/db", "xforms"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xml", "text/xml"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xq*", "application/xquery"),
                setup:create-collection("/db/xforms", "xsltforms"),
                setup:create-collection("/db/xforms", "data"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.properties", "text/plain"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.png", "image/png"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.gif", "image/gif"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.xsl","text/xml"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.js","application/x-javascript"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.css","text/css")
    )
};

declare function setup:importFromURLs() as element()+
{
    (
        setup:report(),

Actions:

            {
                let $includeXmlad := request:get-parameter("xmlad", ()),
                $includeMondial := request:get-parameter("mondial", ()),
 				$includeLocal := request:get-parameter("local", ()) return
                (
					if($includeLocal) then
					( setup:importLocal()
					)
					else (),
                    if($includeXmlad) then
                    (
                        setup:create-collection("/db", "xmlad"),
                        setup:load-URL("/db/xmlad", xs:anyURI("http://surfnet.dl.sourceforge.net/sourceforge/xmlad/xmlad.xml"), "xmlad.xml")
                    )else (),
                    if($includeMondial) then
                    (
                        setup:create-collection("/db", "mondial"),
                        setup:load-URL("/db/mondial", xs:anyURI("http://www.dbis.informatik.uni-goettingen.de/Mondial/mondial-europe.xml"), "mondial.xml")
                    )else ()
                )
            }

    )
};

declare function setup:load-URL($collection as xs:string, $url as xs:anyURI, $docName as xs:string) as element()
{
    let $x := xdb:store($collection, $docName, $url) return

File {$docName} imported from url: {$url}

};

declare function setup:store-files($collection as xs:string, $home as xs:string, $patterns as xs:string, $mimeType as xs:string) as element()*
{
    let $stored := xdb:store-files-from-pattern($collection, $home, $patterns, $mimeType)
    for $doc in $stored return

Uploaded: {$doc}

};

declare function setup:create-collection($parent as xs:string, $name as xs:string) as element()
{
    let $col := xdb:create-collection($parent, $name) return

Created collection: {$col}

};

declare function setup:select() as element()
{
    <form action="{session:encode-url(request:get-uri())}" method="post">

eXist ships with a number of XQuery examples. Some of these
        require certain documents to be stored in the database. The XQuery examples also use some
		XML data not included with the distribution which can be downloaded by selecting
		the checkboxes below.

		<input type="checkbox" name="local" checked="true"/>
		eXist-db shipped files

        <input type="checkbox" name="xmlad"/>
        The XML Acronym Demystifier
        (approx. 384K)

        <input type="checkbox" name="mondial"/>
        The Mondial Database (Europe)
        (approx. 410K)

<input type="submit" name="action" value="Import Files"/>
        <input type="submit" name="action" value="Skip"/>

        <input type="hidden" name="panel" value="setup"/>
    </form>
};

declare function setup:report() as element()
{

Files have been loaded. You can now go to the
    examples page.

};

xquery version "1.0";
(: $Id$ :)
(:
    Module: examples setup
:)

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

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

declare function setup:main() as element()
{

Examples2 Setup

        {
let $action := request:get-parameter("action", ()) return
		if($action) then
		                (
		                    if($action eq "Import Example Data") then
		                    (
		                        setup:importLocal()
		                    )
		                    else if($action eq "Import Files") then
		                    (
		                        setup:importFromURLs()
		                    )
		                    else
		                    (
		                        setup:report()
		                    )
		                )
		                else
		                (
		                    setup:select()
		                )

        }

};

declare function setup:importLocal() as element()+
{
    let $home := system:get-exist-home(),
    $pathSep := util:system-property("file.separator"),
    $dir := if (doc-available(concat("file:///", $home, "/exist-samples/examples.xml"))) then
        (
            concat($home, $pathSep, "exist-samples")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            concat(substring-before($home, "WEB-INF"), "samples")
        )
        else
        (
            concat($home, $pathSep, "samples")
        ),
    $webapp := if (doc-available(concat("file:///", $home, "/webapp/index.xml"))) then
        (
            concat($home, $pathSep, "webapp")
        )
        else if(ends-with($home, "WEB-INF")) then
        (
            substring-before($home, "WEB-INF")
        )
        else
        (
            concat($home, $pathSep, "webapp")
        )
    return (
                setup:create-collection("/db/system/config", "db"),
                setup:create-collection("/db/system/config/db", "shakespeare"),
                setup:store-files("/db/system/config/db/shakespeare", $dir,
                    "shakespeare/collection.xconf", "text/xml"),
                setup:create-collection("/db", "shakespeare"),
                setup:create-collection("/db/shakespeare", "plays"),
                setup:store-files("/db/shakespeare/plays", $dir,  "shakespeare/*.xml", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.xsl", "text/xml"),
                setup:store-files("/db/shakespeare/plays", $dir, "shakespeare/*.css", "text/css"),
                setup:create-collection("/db", "xinclude"),
                setup:create-collection("/db/xinclude", "styles"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xsl", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xml", "text/xml"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.xq", "application/xquery"),
                setup:store-files("/db/xinclude", $dir, "xinclude/*.jpg", "image/jpeg"),
                setup:store-files("/db/xinclude/styles", $dir, "xinclude/styles/*", "text/css"),
                setup:create-collection("/db/xinclude", "scripts"),
                setup:create-collection("/db/xinclude/scripts", "syntax"),
                setup:store-files("/db/xinclude/scripts/syntax", $dir, "xinclude/scripts/syntax/*.js", "application/x-javascript"),
                setup:create-collection("/db", "library"),
                setup:store-files("/db/library", $dir, "*.rdf", "text/xml"),
                setup:create-collection("/db", "mods"),
                setup:store-files("/db/mods", $dir, "mods/*.xml", "text/xml"),
                setup:store-files("/db", $dir, "*.xml", "text/xml"),
                setup:create-collection("/db/system/config/db", "mondial"),
                setup:store-files("/db/system/config/db/mondial", $dir, "mondial.xconf", "text/xml"),
                setup:create-collection("/db", "xproc"),
                setup:create-collection("/db/xproc", "unit-test"),
                setup:create-collection("/db/xproc", "xml"),
                setup:create-collection("/db/xproc", "xslt"),
                setup:create-collection("/db/xproc", "result"),
                setup:create-collection("/db/xproc", "examples"),
                setup:create-collection("/db/xproc", "pipelines"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xml", "text/xml"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xql", "application/xquery"),
                setup:store-files("/db/xproc/unit-test", $webapp, "xproc/unit-test/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/pipelines", $webapp, "xproc/pipelines/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xml", $webapp, "xproc/xml/*.xml", "text/xml"),
                setup:store-files("/db/xproc/xslt", $webapp, "xproc/xml/*.xsl", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xproc", "text/xml"),
                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xml", "text/xml"),

                setup:store-files("/db/xproc/examples", $webapp, "xproc/examples/*.xql", "application/xquery"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xml", "text/xml"),
                setup:store-files("/db/xproc", $webapp, "xproc/*.xql", "application/xquery"),

                setup:create-collection("/db", "xforms"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xml", "text/xml"),
                setup:store-files("/db/xforms", $webapp, "xforms/*.xq*", "application/xquery"),
                setup:create-collection("/db/xforms", "xsltforms"),
                setup:create-collection("/db/xforms", "data"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.properties", "text/plain"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.png", "image/png"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.gif", "image/gif"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.xsl","text/xml"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.js","application/x-javascript"),
                setup:store-files("/db/xforms/xsltforms", $webapp, "xforms/xsltforms/*.css","text/css")
    )
};

declare function setup:importFromURLs() as element()+
{
    (
        setup:report(),

Actions:

            {
                let $includeXmlad := request:get-parameter("xmlad", ()),
                $includeMondial := request:get-parameter("mondial", ()),
 				$includeLocal := request:get-parameter("local", ()) return
                (
					if($includeLocal) then
					( setup:importLocal()
					)
					else (),
                    if($includeXmlad) then
                    (
                        setup:create-collection("/db", "xmlad"),
                        setup:load-URL("/db/xmlad", xs:anyURI("http://surfnet.dl.sourceforge.net/sourceforge/xmlad/xmlad.xml"), "xmlad.xml")
                    )else (),
                    if($includeMondial) then
                    (
                        setup:create-collection("/db", "mondial"),
                        setup:load-URL("/db/mondial", xs:anyURI("http://www.dbis.informatik.uni-goettingen.de/Mondial/mondial-europe.xml"), "mondial.xml")
                    )else ()
                )
            }

    )
};

declare function setup:load-URL($collection as xs:string, $url as xs:anyURI, $docName as xs:string) as element()
{
    let $x := xdb:store($collection, $docName, $url) return

File {$docName} imported from url: {$url}

};

declare function setup:store-files($collection as xs:string, $home as xs:string, $patterns as xs:string, $mimeType as xs:string) as element()*
{
    let $stored := xdb:store-files-from-pattern($collection, $home, $patterns, $mimeType)
    for $doc in $stored return

Uploaded: {$doc}

};

declare function setup:create-collection($parent as xs:string, $name as xs:string) as element()
{
    let $col := xdb:create-collection($parent, $name) return

Created collection: {$col}

};

declare function setup:select() as element()
{
    <form action="{session:encode-url(request:get-uri())}" method="post">

eXist ships with a number of XQuery examples. Some of these
        require certain documents to be stored in the database. The XQuery examples also use some
		XML data not included with the distribution which can be downloaded by selecting
		the checkboxes below.

		<input type="checkbox" name="local" checked="true"/>
		eXist-db shipped files

        <input type="checkbox" name="xmlad"/>
        The XML Acronym Demystifier
        (approx. 384K)

        <input type="checkbox" name="mondial"/>
        The Mondial Database (Europe)
        (approx. 410K)

<input type="submit" name="action" value="Import Files"/>
        <input type="submit" name="action" value="Skip"/>

        <input type="hidden" name="panel" value="setup"/>
    </form>
};

declare function setup:report() as element()
{

Files have been loaded. You can now go to the
    examples page.

};


Added further order by example

Added further order by example

xquery version "3.0";

declare namespace other = "http://other";

declare variable $local:straight-var1 := 'one';

declare %private variable $local:private-var := 'secret';
declare %public variable $local:public-var := 'not-secret';
declare %other:annotation('param1', "param2") variable $local:some-var := 'anything';

declare variable $local:straight-var2 := 'two';

(: Simple Map Operator example :)
declare function local:word-count($elms as element()*) as xs:integer {
	sum($elms ! count(tokenize(., '\s+')))
};

declare function local:add($a, $b) {
	$a + $b
};

declare function local:dispatch($node as node()) as item()* {
    typeswitch($node)
        case text() return $node
        case comment() return $node
        case element(bill) return local:bill($node)
        case element(btitle) return local:btitle($node)
        case element(section-id) return local:section-id($node)
        case element(bill-text) return local:bill-text($node)
        case element(strike) return local:strike($node)
        default return local:passthru($node)
};

(: `switch` expression example :)
declare function local:noise($animal) {
	let $duck := "Duck",
	$quack := "Quack"
	return
		switch ($animal)
			case "Cow" return "Moo"
			case 'Cat' return 'Meow'
			case $duck return $quack
			default return "What's that odd noise?"
};

(: `group by` expression with binding example :)
declare function local:a-to-z() {
	let $data as element()* := (
		<item>Apples</item>,
		<item>Bananas</item>,
		<item>Apricots</item>,
		<item>Pears</item>,
		<item>Brambles</item>
	) return
		<GroupedItems>{
			for $item in $data
			group by $key := upper-case(substring($item, 1, 1))
			order by $key
			return
				<Group key="{$key}">{$item}</Group>
		}</GroupedItems>
};

(: `group by` expression example :)
declare function local:plays-by-character() {
	let $plays := (
		document {
			<play>
				<title>Hamlet</title>
				<characters>
					<character>Hamlet</character>
					<character>Claudius</character>
					<character>Polonius</character>
					<character>Rosencrantz</character>
					<character>Guildenstern</character>
					<character>Francisco</character>
					<character>Reynaldo</character>
				</characters>
			</play>
		},
		document {
			<play>
				<title>Rosenkrantz and Guildenstern are Dead</title>
				<characters>
					<character>Alfred</character>
					<character>Rosencrantz</character>
					<character>Guildenstern</character>
					<character>Hamlet</character>
					<character>Claudius</character>
				</characters>
			</play>
		}
	) return

		for $play in $plays/play
		let $title := $play/title
		for $character in $play/characters/character
		group by $character
		return
			<character name="{$character}">
			{
				$title ! <play>{ . }</play>
     		}
			</character>
};

declare
	%other:a
	%private
	%other:b('1')
	%other:c("1", "2", "3", "4")
function local:very-annotated() {
	let $thing := "thing"
	return
		$thing
};

declare %public function local:slightly-annotated() {
	let $nothing := ()
	return
		$nothing
};

declare function local:ordered() {
	for $hit in doc("/db/doc-with-indexes.xml")//tei:p[other:query(., $search-expression)]
	let $score as xs:float := other:score($hit)
	order by $score descending
	return (

Score: {$score}:
,
		other:summarize($hit, <config width="40"/>)
	)
};

declare function local:merge-simple($a as xs:string+, $b as xs:string+) as xs:string+ {
	($a, $b)
};

(: higher order function example 1 :)
declare function local:apply($func, $value) {
	$func($value)
};

(: higher order function example 2 :)
declare function local:apply-all($func, $list) {
	$list ! $func(.)
};

(: higher order function example 3 :)
declare function local:apply-all-long($func as function(xs:string) as xs:string, $list) {
	$list ! $func(.)
};

(: higher order function example 4 :)
declare function local:merge($func as function(xs:string+, xs:string+) as xs:string+, $a as xs:string+, $b as xs:string+) as xs:string+ {
	$func($a, $b)
};

let $to-upper := upper-case#1
let $to-upper-long as function(xs:string) as xs:string := upper-case#1
return
    <case>
    {
        local:apply-all($to-upper, ("Hello", "world!")) ! <upper>{.}</upper>,
        local:apply-all-long(lower-case#1, ("Hello", "world!")) ! <lower>{.}</lower>
    }
    </case>

xquery version "3.0";

declare namespace other = "http://other";

declare variable $local:straight-var1 := 'one';

declare %private variable $local:private-var := 'secret';
declare %public variable $local:public-var := 'not-secret';
declare %other:annotation('param1', "param2") variable $local:some-var := 'anything';

declare variable $local:straight-var2 := 'two';

(: Simple Map Operator example :)
declare function local:word-count($elms as element()*) as xs:integer {
	sum($elms ! count(tokenize(., '\s+')))
};

declare function local:add($a, $b) {
	$a + $b
};

declare function local:dispatch($node as node()) as item()* {
    typeswitch($node)
        case text() return $node
        case comment() return $node
        case element(bill) return local:bill($node)
        case element(btitle) return local:btitle($node)
        case element(section-id) return local:section-id($node)
        case element(bill-text) return local:bill-text($node)
        case element(strike) return local:strike($node)
        default return local:passthru($node)
};

(: `switch` expression example :)
declare function local:noise($animal) {
	let $duck := "Duck",
	$quack := "Quack"
	return
		switch ($animal)
			case "Cow" return "Moo"
			case 'Cat' return 'Meow'
			case $duck return $quack
			default return "What's that odd noise?"
};

(: `group by` expression with binding example :)
declare function local:a-to-z() {
	let $data as element()* := (
		<item>Apples</item>,
		<item>Bananas</item>,
		<item>Apricots</item>,
		<item>Pears</item>,
		<item>Brambles</item>
	) return
		<GroupedItems>{
			for $item in $data
			group by $key := upper-case(substring($item, 1, 1))
			order by $key
			return
				<Group key="{$key}">{$item}</Group>
		}</GroupedItems>
};

(: `group by` expression example :)
declare function local:plays-by-character() {
	let $plays := (
		document {
			<play>
				<title>Hamlet</title>
				<characters>
					<character>Hamlet</character>
					<character>Claudius</character>
					<character>Polonius</character>
					<character>Rosencrantz</character>
					<character>Guildenstern</character>
					<character>Francisco</character>
					<character>Reynaldo</character>
				</characters>
			</play>
		},
		document {
			<play>
				<title>Rosenkrantz and Guildenstern are Dead</title>
				<characters>
					<character>Alfred</character>
					<character>Rosencrantz</character>
					<character>Guildenstern</character>
					<character>Hamlet</character>
					<character>Claudius</character>
				</characters>
			</play>
		}
	) return

		for $play in $plays/play
		let $title := $play/title
		for $character in $play/characters/character
		group by $character
		return
			<character name="{$character}">
			{
				$title ! <play>{ . }</play>
     		}
			</character>
};

declare
	%other:a
	%private
	%other:b('1')
	%other:c("1", "2", "3", "4")
function local:very-annotated() {
	let $thing := "thing"
	return
		$thing
};

declare %public function local:slightly-annotated() {
	let $nothing := ()
	return
		$nothing
};

declare function local:merge-simple($a as xs:string+, $b as xs:string+) as xs:string+ {
	($a, $b)
};

(: higher order function example 1 :)
declare function local:apply($func, $value) {
	$func($value)
};

(: higher order function example 2 :)
declare function local:apply-all($func, $list) {
	$list ! $func(.)
};

(: higher order function example 3 :)
declare function local:apply-all-long($func as function(xs:string) as xs:string, $list) {
	$list ! $func(.)
};

(: higher order function example 4 :)
declare function local:merge($func as function(xs:string+, xs:string+) as xs:string+, $a as xs:string+, $b as xs:string+) as xs:string+ {
	$func($a, $b)
};

let $to-upper := upper-case#1
let $to-upper-long as function(xs:string) as xs:string := upper-case#1
return
    <case>
    {
        local:apply-all($to-upper, ("Hello", "world!")) ! <upper>{.}</upper>,
        local:apply-all-long(lower-case#1, ("Hello", "world!")) ! <lower>{.}</lower>
    }
    </case>