sending 5 items as a list instead of sending 5 parameters

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

(:Import other namespaces.  :)
import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_mcs = "https://github.com/openhie/openinfoman/csd_mcs";
import module namespace functx = "http://www.functx.com";
import module namespace json = "http://basex.org/modules/json";
import module namespace request = "http://exquery.org/ns/request";

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

declare function page:is_rapidpro($search_name) {
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $ext := $function//csd:extension[  @urn='urn:openhie.org:openinfoman:adapter' and @type='rapidpro']
  return (count($ext) > 0)
};

declare function page:get_actions($search_name) {
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  return
    (
    for $act in $function//csd:extension[  @urn='urn:openhie.org:openinfoman:adapter:rapidpro:action']/@type
    return string($act)
  )
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/rapidpro")
  %output:method("xhtml")
  function page:show_endpoints($search_name,$doc_name)
{
    if (not(page:is_rapidpro($search_name)) )
      then ('Not a RapidPro Compatible stored function'    )
    else
      let $actions := page:get_actions($search_name)
      let $contents :=

RapidPro Operations on {$doc_name}

        {
          if ($actions = 'get')
	  then

JSON Contacts  -- GET

	     {
	       let $url := csd_webui:generateURL(("CSD/csr/" , $doc_name , "/careServicesRequest/",$search_name, "/adapter/rapidpro/get"))
	       return
Get Contacts

	     }

	  else ()
	}

        {
          if ($actions = 'WebHookGET')
	  then

WebHook  -- GET

	     {
	       let $url := csd_webui:generateURL(("CSD/csr/" , $doc_name , "/careServicesRequest/",$search_name, "/adapter/rapidpro/createDXF"))
	       return
WebHook defined at {$url}

	     }

	  else ()
	}
        {
          if ($actions = 'WebHookPOST')
	  then

WebHook  -- POST

	     {
	       let $url := csd_webui:generateURL(("CSD/csr/" , $doc_name , "/careServicesRequest/",$search_name, "/adapter/rap/createDXF"))
	       return
WebHook defined at {$url}

	     }

	  else ()
	}

      return csd_webui:wrapper($contents)
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/rapidpro/WebHook")
  %rest:query-param("event","{$event}")
  %rest:query-param("relayer","{$relayer}")
  %rest:query-param("relayer_phone","{$relayer_phone}")
  %rest:query-param("phone","{$phone}")
  %rest:query-param("flow","{$flow}")
  %rest:query-param("step","{$step}")
  %rest:query-param("values","{$values}")
  %output:media-type("application/json")
  %rest:POST
  %rest:GET
  function page:webhook($search_name,$doc_name,$event,$relayer,$relayer_phone,$phone,$flow,$step,$values)
{
  if (not(page:is_rapidpro($search_name)) )
    then ('Not a RapidPro Compatible stored function'    )
  else
    let $doc :=  csd_dm:open_document($csd_webconf:db,$doc_name)
    let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)

    let $careServicesRequest :=
      <csd:careServicesRequest>
       <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
         <csd:requestParams >
	   <event type="{$event}"/>
	   <relayer id="{$relayer}"/>
	   <relayer_phone number="{$relayer_phone}"/>
	   <phone number="{$phone}"/>
	   <flow id="{$flow}"/>
	   <step id="{$step}"/>
           <values>
	     {
	       if ($values)
	       then    json:parse($values,map{'format':'attributes'})/json/*
	       else ()
	     }
	   </values>
	   {
	     for $param in request:parameter-names()
	     return <query name="{$param}">{request:parameter($param)}</query>
	   }
         </csd:requestParams>
       </csd:function>
      </csd:careServicesRequest>
    return csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest)
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/rapidpro/get")
  function page:get($search_name,$doc_name)
{
  if (not(page:is_rapidpro($search_name)) )
    then

    {csr_proc:get_function_definition($csd_webconf:db,$search_name)}
    {(concat('Not a RapidPro Compatible stored function: ', $search_name )    )}

  else
    let $doc :=  csd_dm:open_document($csd_webconf:db,$doc_name)
    let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)

    let $careServicesRequest :=
      <csd:careServicesRequest>
       <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
         <csd:requestParams/>
       </csd:function>
     </csd:careServicesRequest>
    let $content := csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest)
    let $output := $function/@content-type
    let $mime :=
      if (exists($output))
      then string($output)
      else "text/html"
    return
    (
      <rest:response>
	<http:response status="200" >
          <http:header name='Content-Type' value="{$mime}"/>
	  <http:header name='Content-Disposition' value="attachment; filename='{$doc_name}.json'"/>
	</http:response>
      </rest:response>
      ,$content
    )

};

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

(:Import other namespaces.  :)
import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csd_webui =  "https://github.com/openhie/openinfoman/csd_webui";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
import module namespace csd_mcs = "https://github.com/openhie/openinfoman/csd_mcs";
import module namespace functx = "http://www.functx.com";
import module namespace json = "http://basex.org/modules/json";
import module namespace request = "http://exquery.org/ns/request";

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

declare function page:is_rapidpro($search_name) {
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  let $ext := $function//csd:extension[  @urn='urn:openhie.org:openinfoman:adapter' and @type='rapidpro']
  return (count($ext) > 0)
};

declare function page:get_actions($search_name) {
  let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)
  return
    (
    for $act in $function//csd:extension[  @urn='urn:openhie.org:openinfoman:adapter:rapidpro:action']/@type
    return string($act)
  )
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/rapidpro")
  %output:method("xhtml")
  function page:show_endpoints($search_name,$doc_name)
{
    if (not(page:is_rapidpro($search_name)) )
      then ('Not a RapidPro Compatible stored function'    )
    else
      let $actions := page:get_actions($search_name)
      let $contents :=

RapidPro Operations on {$doc_name}

        {
          if ($actions = 'get')
	  then

JSON Contacts  -- GET

	     {
	       let $url := csd_webui:generateURL( "CSD/csr/" , $doc_name , "/careServicesRequest/",$search_name, "/adapter/rapidpro/get")
	       return
Get Contacts

	     }

	  else ()
	}

        {
          if ($actions = 'WebHookGET')
	  then

WebHook  -- GET

	     {
	       let $url := csd_webui:generateURL( "CSD/csr/" , $doc_name , "/careServicesRequest/",$search_name, "/adapter/rapidpro/createDXF")
	       return
WebHook defined at {$url}

	     }

	  else ()
	}
        {
          if ($actions = 'WebHookPOST')
	  then

WebHook  -- POST

	     {
	       let $url := csd_webui:generateURL( "CSD/csr/" , $doc_name , "/careServicesRequest/",$search_name, "/adapter/rap/createDXF")
	       return
WebHook defined at {$url}

	     }

	  else ()
	}

      return csd_webui:wrapper($contents)
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/rapidpro/WebHook")
  %rest:query-param("event","{$event}")
  %rest:query-param("relayer","{$relayer}")
  %rest:query-param("relayer_phone","{$relayer_phone}")
  %rest:query-param("phone","{$phone}")
  %rest:query-param("flow","{$flow}")
  %rest:query-param("step","{$step}")
  %rest:query-param("values","{$values}")
  %output:media-type("application/json")
  %rest:POST
  %rest:GET
  function page:webhook($search_name,$doc_name,$event,$relayer,$relayer_phone,$phone,$flow,$step,$values)
{
  if (not(page:is_rapidpro($search_name)) )
    then ('Not a RapidPro Compatible stored function'    )
  else
    let $doc :=  csd_dm:open_document($csd_webconf:db,$doc_name)
    let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)

    let $careServicesRequest :=
      <csd:careServicesRequest>
       <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
         <csd:requestParams >
	   <event type="{$event}"/>
	   <relayer id="{$relayer}"/>
	   <relayer_phone number="{$relayer_phone}"/>
	   <phone number="{$phone}"/>
	   <flow id="{$flow}"/>
	   <step id="{$step}"/>
           <values>
	     {
	       if ($values)
	       then    json:parse($values,map{'format':'attributes'})/json/*
	       else ()
	     }
	   </values>
	   {
	     for $param in request:parameter-names()
	     return <query name="{$param}">{request:parameter($param)}</query>
	   }
         </csd:requestParams>
       </csd:function>
      </csd:careServicesRequest>
    return csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest)
};

declare
  %rest:path("/CSD/csr/{$doc_name}/careServicesRequest/{$search_name}/adapter/rapidpro/get")
  function page:get($search_name,$doc_name)
{
  if (not(page:is_rapidpro($search_name)) )
    then

    {csr_proc:get_function_definition($csd_webconf:db,$search_name)}
    {(concat('Not a RapidPro Compatible stored function: ', $search_name )    )}

  else
    let $doc :=  csd_dm:open_document($csd_webconf:db,$doc_name)
    let $function := csr_proc:get_function_definition($csd_webconf:db,$search_name)

    let $careServicesRequest :=
      <csd:careServicesRequest>
       <csd:function urn="{$search_name}" resource="{$doc_name}" base_url="{csd_webui:generateURL()}">
         <csd:requestParams/>
       </csd:function>
     </csd:careServicesRequest>
    let $content := csr_proc:process_CSR_stored_results($csd_webconf:db, $doc,$careServicesRequest)
    let $output := $function/@content-type
    let $mime :=
      if (exists($output))
      then string($output)
      else "text/html"
    return
    (
      <rest:response>
	<http:response status="200" >
          <http:header name='Content-Type' value="{$mime}"/>
	  <http:header name='Content-Disposition' value="attachment; filename='{$doc_name}.json'"/>
	</http:response>
      </rest:response>
      ,$content
    )

};


Fix #238 Don't use the window.location.assign function in logout

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

module namespace calli = "http://callimachusproject.org/rdf/2009/framework#";

declare copy-namespaces preserve, inherit;
declare default element namespace "http://www.w3.org/1999/xhtml";

declare variable $calli:realm external;

(: template nodes :)
declare variable $calli:html-element := /html;

declare function calli:head-nodes() as node()* {
    $calli:html-element/head/node()
};
declare function calli:body-attributes() as attribute(*)* {
    $calli:html-element/body/@*
};
declare function calli:body-nodes() as node()* {
    $calli:html-element/body/node()
};
declare function calli:head-links($a as element(), $divider as element()) as element()* {
    let $links := $calli:html-element/head/link[@title and @href]
    return if ($links) then
        (
            for $link in $links
            return calli:add-href($a, $link, $link/@title),
            $divider
        )
    else
        $links
};
declare function calli:add-href($a as element(), $link as element(), $label as xs:string) {
    if (local-name($a)='a') then
        element {node-name($a)} {
            $a/@*[name()!='class'],
            for $attr in $link/@*[name()!='id']
            return if ($a/@*[name()=name($attr)]) then ()
            else $attr,
            if ($a/@class and $link/@class) then attribute class {concat($a/@class,' ',$link/@class)}
            else if ($a/@class) then $a/@class
            else (),
            $label
        }
    else if ($a/self::*) then
        element {node-name($a)} {
            $a/@*,
            for $node in $a/node()
            return calli:add-href($node, $link, $label)
        }
    else
        $a

};

(: static markup functions :)
declare function calli:styles-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {resolve-uri('../styles/callimachus.less?less')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:scripts-src($script as element()) as element() {
    element {node-name($script)} {
        attribute src {resolve-uri('../../scripts.js')},
        $script/@*[name()!='src'],
        $script/node()
    }
};
declare function calli:lookup-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {concat($calli:realm, '?q')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:lookup-form($placeholder as xs:string) as element(form) {
    <form class="navbar-form" role="search" method="GET" action="{$calli:realm}">

            <input type="text" name="q" class="form-control pull-right" placeholder="{$placeholder}" />

                <button class="btn btn-default" type="submit">

                    Search
                </button>

    </form>
};
declare function calli:callimachus-about-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://callimachusproject.org/'},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-getting-started-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {resolve-uri('../../getting-started-with-callimachus')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-feedback-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://groups.google.com/group/callimachus-discuss'},
        $a/@*[name()!='href'],
        $a/node()
    }
};

declare function calli:breadcrumb-list($ol as element()) as element(nav) {
    {
        element {node-name($ol)} {
            $ol/@*,
            $ol/node(),

        }
    }
};
declare function calli:breadcrumb-links($breadcrumb as element(), $divider as item(), $active as element()) as element(nav) {
    {$breadcrumb}{$divider}{$active}
};
declare function calli:breadcrumb-links($breadcrumb as item()*, $active as element()) as element(nav) {
    {$breadcrumb}{$active}
};
declare function calli:activate-nav($nav as node()*) as element(nav) {
    {$nav}
};
declare function calli:lastmod-time($time as element()) as element(div) {

{$time}

};
declare function calli:error-alert($div as element()) as element(div) {

{$div}

};
declare function calli:generator-p($p as element()) as element() {
    element { node-name($p) } {
        $p/@*,
        $p/node(),

    }
};

(: navigation links :)
declare function calli:home-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {$calli:realm},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:folder-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?view')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:changes-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?changes')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:view-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?view"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:edit-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?edit"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:discussion-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?discussion"},
        $a/@*[name()!='href'],
        ,
        $a/node()
    }
};
declare function calli:describe-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?describe"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:history-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?history"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:whatlinkshere-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?whatlinkshere"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:relatedchanges-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?relatedchanges"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:permissions-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?permissions"},
        if ($a/@onclick) then $a/@onclick
            else attribute onclick {"if(location.search!='?view')return true;calli.openDialog(this.href,this.textContent);return false;"},
        $a/@*[name()!='href' and name()!='click'],
        $a/node()
    }
};
declare function calli:introspect-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?introspect"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:admin-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {resolve-uri('../pages/invite-users.xhtml?view')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:login-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?login')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:profile-href($a as element()) as element()+ {
    (element {node-name($a)} {
        attribute href {concat($calli:realm,'?profile')},
        $a/@*[name()!='href'],
        $a/node()
    }, )
};
declare function calli:logout-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {$calli:realm},
        attribute onclick {concat('calli.logout("',$calli:realm,'").then(function(){location="',$calli:realm,'";}).then(undefined, calli.loading(event.target));return false')},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};

(: deprecated since 1.3 :)
declare function calli:body-sidebar($div as element()) as element()? {
    ()
};
declare function calli:body-hgroup() as element()? {
    ()
};

(: deprecated since 1.2 :)
declare function calli:breadcrumb-nav($breadcrumb as element()) as element(nav) {
    {$breadcrumb}
};

(: deprecated since 1.0.1 :)
declare function calli:styles() as element() {calli:styles-href(<link rel="stylesheet" />)};
declare function calli:scripts() as element() {calli:scripts-src(

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

module namespace calli = "http://callimachusproject.org/rdf/2009/framework#";

declare copy-namespaces preserve, inherit;
declare default element namespace "http://www.w3.org/1999/xhtml";

declare variable $calli:realm external;

(: template nodes :)
declare variable $calli:html-element := /html;

declare function calli:head-nodes() as node()* {
    $calli:html-element/head/node()
};
declare function calli:body-attributes() as attribute(*)* {
    $calli:html-element/body/@*
};
declare function calli:body-nodes() as node()* {
    $calli:html-element/body/node()
};
declare function calli:head-links($a as element(), $divider as element()) as element()* {
    let $links := $calli:html-element/head/link[@title and @href]
    return if ($links) then
        (
            for $link in $links
            return calli:add-href($a, $link, $link/@title),
            $divider
        )
    else
        $links
};
declare function calli:add-href($a as element(), $link as element(), $label as xs:string) {
    if (local-name($a)='a') then
        element {node-name($a)} {
            $a/@*[name()!='class'],
            for $attr in $link/@*[name()!='id']
            return if ($a/@*[name()=name($attr)]) then ()
            else $attr,
            if ($a/@class and $link/@class) then attribute class {concat($a/@class,' ',$link/@class)}
            else if ($a/@class) then $a/@class
            else (),
            $label
        }
    else if ($a/self::*) then
        element {node-name($a)} {
            $a/@*,
            for $node in $a/node()
            return calli:add-href($node, $link, $label)
        }
    else
        $a

};

(: static markup functions :)
declare function calli:styles-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {resolve-uri('../styles/callimachus.less?less')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:scripts-src($script as element()) as element() {
    element {node-name($script)} {
        attribute src {resolve-uri('../../scripts.js')},
        $script/@*[name()!='src'],
        $script/node()
    }
};
declare function calli:lookup-href($link as element()) as element() {
    element {node-name($link)} {
        attribute href {concat($calli:realm, '?q')},
        $link/@*[name()!='href'],
        $link/node()
    }
};
declare function calli:lookup-form($placeholder as xs:string) as element(form) {
    <form class="navbar-form" role="search" method="GET" action="{$calli:realm}">

            <input type="text" name="q" class="form-control pull-right" placeholder="{$placeholder}" />

                <button class="btn btn-default" type="submit">

                    Search
                </button>

    </form>
};
declare function calli:callimachus-about-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://callimachusproject.org/'},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-getting-started-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {resolve-uri('../../getting-started-with-callimachus')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:callimachus-feedback-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {'http://groups.google.com/group/callimachus-discuss'},
        $a/@*[name()!='href'],
        $a/node()
    }
};

declare function calli:breadcrumb-list($ol as element()) as element(nav) {
    {
        element {node-name($ol)} {
            $ol/@*,
            $ol/node(),

        }
    }
};
declare function calli:breadcrumb-links($breadcrumb as element(), $divider as item(), $active as element()) as element(nav) {
    {$breadcrumb}{$divider}{$active}
};
declare function calli:breadcrumb-links($breadcrumb as item()*, $active as element()) as element(nav) {
    {$breadcrumb}{$active}
};
declare function calli:activate-nav($nav as node()*) as element(nav) {
    {$nav}
};
declare function calli:lastmod-time($time as element()) as element(div) {

{$time}

};
declare function calli:error-alert($div as element()) as element(div) {

{$div}

};
declare function calli:generator-p($p as element()) as element() {
    element { node-name($p) } {
        $p/@*,
        $p/node(),

    }
};

(: navigation links :)
declare function calli:home-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {$calli:realm},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:folder-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?view')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:changes-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?changes')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:view-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?view"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:edit-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?edit"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:discussion-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?discussion"},
        $a/@*[name()!='href'],
        ,
        $a/node()
    }
};
declare function calli:describe-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?describe"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:history-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?history"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:whatlinkshere-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?whatlinkshere"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:relatedchanges-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?relatedchanges"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:permissions-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?permissions"},
        if ($a/@onclick) then $a/@onclick
            else attribute onclick {"if(location.search!='?view')return true;calli.openDialog(this.href,this.textContent);return false;"},
        $a/@*[name()!='href' and name()!='click'],
        $a/node()
    }
};
declare function calli:introspect-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {"?introspect"},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:admin-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {resolve-uri('../pages/invite-users.xhtml?view')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:login-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {concat($calli:realm,'?login')},
        $a/@*[name()!='href'],
        $a/node()
    }
};
declare function calli:profile-href($a as element()) as element()+ {
    (element {node-name($a)} {
        attribute href {concat($calli:realm,'?profile')},
        $a/@*[name()!='href'],
        $a/node()
    }, )
};
declare function calli:logout-href($a as element()) as element() {
    element {node-name($a)} {
        attribute href {$calli:realm},
        attribute onclick {concat('calli.logout("',$calli:realm,'").then(location.assign.bind(location,"',$calli:realm,'")).then(undefined, calli.loading(event.target));return false')},
        $a/@*[name()!='href' and name()!='id'],
        $a/node()
    }
};

(: deprecated since 1.3 :)
declare function calli:body-sidebar($div as element()) as element()? {
    ()
};
declare function calli:body-hgroup() as element()? {
    ()
};

(: deprecated since 1.2 :)
declare function calli:breadcrumb-nav($breadcrumb as element()) as element(nav) {
    {$breadcrumb}
};

(: deprecated since 1.0.1 :)
declare function calli:styles() as element() {calli:styles-href(<link rel="stylesheet" />)};
declare function calli:scripts() as element() {calli:scripts-src(


Added input context when test fails.
Had to comment it though because of an in-memory document size limit

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

declare namespace xqts="http://exist-db.org/xquery/xqts";
declare namespace catalog="http://www.w3.org/2005/02/query-test-XQTSCatalog";

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

(:~ ----------------------------------------------------------------------------------------
     W3C XQuery Test Suite

     This is the main module for running the XQTS on eXist. You can either
     run the whole test suite, a specific test group or a single test case.

     Setup:

     * Make sure the XmlDiff module is registered in conf.xml

     * Change the $xqts:XQTS_HOME variable below to point to the directory into
     which you unzipped the XQTS sources.

     * Create a collection /db/XQTS in the database.

     * From the XQTS directory, upload XQTSCatalog.xml into the created
     collection.

     * Upload the "TestSources" directory so the source docs can be found
     in /db/XQTS/TestSources.

     * Run this script with the client.
     ------------------------------------------------------------------------------------------- :)
declare variable $xqts:XQTS_HOME { "file:///d:/Data/XQTS/" };

declare function xqts:initialize() as empty() {
    let $output-coll := xdb:create-collection("/db/XQTS", "test-results")
    let $dummy := xdb:store("/db/XQTS/test-results", "results.xml", <test-result failed="0" passed="0"/>)
    return ()
};

declare function xqts:get-query($case as element(catalog:test-case)) {
   let $query-name := $case//catalog:query/@name
   let $path := concat( $xqts:XQTS_HOME, "Queries/XQuery/", $case/@FilePath, $query-name, ".xq" )
   let $xq-string := util:file-read($path)
   return $xq-string
};

declare function xqts:print-result($test-name as xs:string, $passed as xs:boolean, $query as xs:string,
    $result as item()*, $expected as item()*, $case as element(catalog:test-case)) as element() {
    <test-case name="{$test-name}" result="{if ($passed) then 'pass' else 'fail'}">
    {
        if (not($passed)) then (
            <result>{$result}</result>,
            <expected>{$expected}</expected>,
            (: element {$case/catalog:input-file/@variable} { xqts:getInputValue($case) }, :)
            <query>{$query}</query>
        ) else ()
    }
    </test-case>
};

declare function xqts:check-output($query as xs:string, $result as item()*, $case as element(catalog:test-case)) {
    let $output := $case/catalog:output-file[last()]
    return
        if ($output/@compare eq "Text") then
            let $text := util:file-read(concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                "/", $output/text()))
            let $test := $text eq string($result[1])
            return
                xqts:print-result($case/@name, $test, $query, $result, $text, $case)
        else if ($output/@compare eq "XML") then
            let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                $output/text())
            let $expected := doc(xdb:store("/db", "temp.xml", xs:anyURI($filePath), "text/xml"))
            let $test := xdiff:compare($expected, $result)
            return
                xqts:print-result($case/@name, $test, $query, $result, $expected, $case)
        else if ($output/@compare eq "Fragment") then
            let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath, $output/text())
            let $xmlFrag := concat("<f>", util:file-read($filePath), "</f>")
            let $log := util:log("DEBUG", ("Frag stored: ", $xmlFrag))
            let $expected := doc(xdb:store("/db", "temp.xml", $xmlFrag, "text/xml"))
            let $test := xdiff:compare($expected, <f>{$result}</f>)
            return
                xqts:print-result($case/@name, $test, $query, $result, $expected, $case)
        else
            <error test="{$case/@name}">Unknown comparison method: {$output/@compare}.</error>
};

declare function xqts:run-test-case( $case as element(catalog:test-case)) as item()* {
   let $query := xqts:get-query($case)
   let $input-value := xqts:getInputValue($case)
   let $context :=
       <static-context>
           <variable name="{$case/catalog:input-file/@variable}">{$input-value}</variable>
       </static-context>
   let $result :=
       util:catch("org.exist.xquery.XPathException",
           let $result :=
               util:eval-with-context($query, $context, false())
           return
               xqts:check-output($query, $result, $case),
           if (exists($case/catalog:expected-error)) then
               <test-case name="{$case/@name}" result="pass"/>
           else
               <test-case name="{$case/@name}" result="fail">
                   <exception>{$util:exception-message}</exception>
                   <query>{$query}</query>
               </test-case>
       )
   return $result
};

declare function xqts:finish() as empty() {
    let $result := doc("/db/XQTS/test-results/results.xml")/test-result
    let $passed := count($result//test-case[@result = 'pass'])
    let $failed := count($result//test-case[@result = 'fail'])
    return (
        update value $result/@passed with xs:int($passed),
        update value $result/@failed with xs:int($failed)
    )
};

declare function xqts:run-single-test-case($case as element(catalog:test-case),
    $group as element()?) as empty() {
    let $result := xqts:run-test-case($case)
    return
        if ($group) then
            update insert $result into $group
        else
            update insert $result into doc("/db/XQTS/test-results/results.xml")/test-result
};

declare function xqts:run-test-group($group as element(catalog:test-group),
    $parent as element()?) as empty() {
    update insert <test-group name="{$group/@name}">{$group/catalog:GroupInfo}</test-group>
        into $parent,
    let $newGroup := $parent/test-group[last()]
    return (
        for $test in $group/catalog:test-case
        let $log := util:log("DEBUG", ("Running test case: ", string($test/@name)))
        return
            xqts:run-single-test-case($test, $newGroup),
        for $childGroup in $group/catalog:test-group
        let $log := util:log("DEBUG", ("Entering group: ", string($childGroup/@name)))
        return
            xqts:run-test-group($childGroup, $newGroup)
    )
};

declare function xqts:test-single($name as xs:string) as empty() {
    let $test := //catalog:test-case[@name = $name]
    return
        xqts:run-single-test-case($test, collection("/db/XQTS/test-results")/test-result)
};

declare function xqts:test-group($groupName as xs:string) as empty() {
    let $group := //catalog:test-group[@name = $groupName]
    return
        xqts:run-test-group($group, collection("/db/XQTS/test-results")/test-result)
};

declare function xqts:test-all() as empty() {
    for $test in /catalog:test-suite/catalog:test-group
    return
        xqts:test-group($test/@name)
};

declare function xqts:getInputValue($case as element(catalog:test-case)) as item()* {
	let $input := $case/catalog:input-file
  	return
       if ($input eq "emptydoc") then
           ()
       else (
           let $source := root($case)//catalog:source[@ID = $input/text()]
           return
               if (empty($source)) then
                   concat("no input found: ", $input/text())
               else
                   doc(concat("/db/XQTS/", $source/@FileName))
       )
};

xqts:initialize(),
(: xqts:test-single("Axes001"), :)
xqts:test-group("PathExpr"),
xqts:finish(),
doc("/db/XQTS/test-results/results.xml")

declare namespace xqts="http://exist-db.org/xquery/xqts";
declare namespace catalog="http://www.w3.org/2005/02/query-test-XQTSCatalog";

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

(:~ ----------------------------------------------------------------------------------------
     W3C XQuery Test Suite

     This is the main module for running the XQTS on eXist. You can either
     run the whole test suite, a specific test group or a single test case.

     Setup:

     * Make sure the XmlDiff module is registered in conf.xml

     * Change the $xqts:XQTS_HOME variable below to point to the directory into
     which you unzipped the XQTS sources.

     * Create a collection /db/XQTS in the database.

     * From the XQTS directory, upload XQTSCatalog.xml into the created
     collection.

     * Upload the "TestSources" directory so the source docs can be found
     in /db/XQTS/TestSources.

     * Run this script with the client.
     ------------------------------------------------------------------------------------------- :)
declare variable $xqts:XQTS_HOME { "file:///d:/Data/XQTS/" };

declare function xqts:initialize() as empty() {
    let $output-coll := xdb:create-collection("/db/XQTS", "test-results")
    let $dummy := xdb:store("/db/XQTS/test-results", "results.xml", <test-result failed="0" passed="0"/>)
    return ()
};

declare function xqts:get-query($case as element(catalog:test-case)) {
   let $query-name := $case//catalog:query/@name
   let $path := concat( $xqts:XQTS_HOME, "Queries/XQuery/", $case/@FilePath, $query-name, ".xq" )
   let $xq-string := util:file-read($path)
   return $xq-string
};

declare function xqts:print-result($test-name as xs:string, $passed as xs:boolean, $query as xs:string,
    $result as item()*, $expected as item()*) as element() {
    <test-case name="{$test-name}" result="{if ($passed) then 'pass' else 'fail'}">
    {
        if (not($passed)) then (
            <result>{$result}</result>,
            <expected>{$expected}</expected>,
            <query>{$query}</query>
        ) else ()
    }
    </test-case>
};

declare function xqts:check-output($query as xs:string, $result as item()*, $case as element(catalog:test-case)) {
    let $output := $case/catalog:output-file[last()]
    return
        if ($output/@compare eq "Text") then
            let $text := util:file-read(concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                "/", $output/text()))
            let $test := $text eq string($result[1])
            return
                xqts:print-result($case/@name, $test, $query, $result, $text)
        else if ($output/@compare eq "XML") then
            let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath,
                $output/text())
            let $expected := doc(xdb:store("/db", "temp.xml", xs:anyURI($filePath), "text/xml"))
            let $test := xdiff:compare($expected, $result)
            return
                xqts:print-result($case/@name, $test, $query, $result, $expected)
        else if ($output/@compare eq "Fragment") then
            let $filePath := concat($xqts:XQTS_HOME, "ExpectedTestResults/", $case/@FilePath, $output/text())
            let $xmlFrag := concat("<f>", util:file-read($filePath), "</f>")
            let $log := util:log("DEBUG", ("Frag stored: ", $xmlFrag))
            let $expected := doc(xdb:store("/db", "temp.xml", $xmlFrag, "text/xml"))
            let $test := xdiff:compare($expected, <f>{$result}</f>)
            return
                xqts:print-result($case/@name, $test, $query, $result, $expected)
        else
            <error test="{$case/@name}">Unknown comparison method: {$output/@compare}.</error>
};

declare function xqts:run-test-case( $case as element(catalog:test-case)) as item()* {
   let $query := xqts:get-query($case)
   let $input := $case/catalog:input-file
   let $input-value :=
       if ($input eq "emptydoc") then
           ()
       else (
           let $source := root($case)//catalog:source[@ID = $input/text()]
           return
               if (empty($source)) then
                   concat("no input found: ", $input/text())
               else
                   doc(concat("/db/XQTS/", $source/@FileName))
       )
   let $context :=
       <static-context>
           <variable name="{$input/@variable}">{$input-value}</variable>
       </static-context>
   let $result :=
       util:catch("org.exist.xquery.XPathException",
           let $result :=
               util:eval-with-context($query, $context, false())
           return
               xqts:check-output($query, $result, $case),
           if (exists($case/catalog:expected-error)) then
               <test-case name="{$case/@name}" result="pass"/>
           else
               <test-case name="{$case/@name}" result="fail">
                   <exception>{$util:exception-message}</exception>
                   <query>{$query}</query>
               </test-case>
       )
   return $result
};

declare function xqts:finish() as empty() {
    let $result := doc("/db/XQTS/test-results/results.xml")/test-result
    let $passed := count($result//test-case[@result = 'pass'])
    let $failed := count($result//test-case[@result = 'fail'])
    return (
        update value $result/@passed with xs:int($passed),
        update value $result/@failed with xs:int($failed)
    )
};

declare function xqts:run-single-test-case($case as element(catalog:test-case),
    $group as element()?) as empty() {
    let $result := xqts:run-test-case($case)
    return
        if ($group) then
            update insert $result into $group
        else
            update insert $result into doc("/db/XQTS/test-results/results.xml")/test-result
};

declare function xqts:run-test-group($group as element(catalog:test-group),
    $parent as element()?) as empty() {
    update insert <test-group name="{$group/@name}">{$group/catalog:GroupInfo}</test-group>
        into $parent,
    let $newGroup := $parent/test-group[last()]
    return (
        for $test in $group/catalog:test-case
        let $log := util:log("DEBUG", ("Running test case: ", string($test/@name)))
        return
            xqts:run-single-test-case($test, $newGroup),
        for $childGroup in $group/catalog:test-group
        let $log := util:log("DEBUG", ("Entering group: ", string($childGroup/@name)))
        return
            xqts:run-test-group($childGroup, $newGroup)
    )
};

declare function xqts:test-single($name as xs:string) as empty() {
    let $test := //catalog:test-case[@name = $name]
    return
        xqts:run-single-test-case($test, collection("/db/XQTS/test-results")/test-result)
};

declare function xqts:test-group($groupName as xs:string) as empty() {
    let $group := //catalog:test-group[@name = $groupName]
    return
        xqts:run-test-group($group, collection("/db/XQTS/test-results")/test-result)
};

declare function xqts:test-all() as empty() {
    for $test in /catalog:test-suite/catalog:test-group
    return
        xqts:test-group($test/@name)
};

xqts:initialize(),
(: xqts:test-single("Axes001"), :)
xqts:test-group("PathExpr"),
xqts:finish(),
doc("/db/XQTS/test-results/results.xml")


Moved to tags.xq

Moved to tags.xq

declare default element namespace "http://www.w3.org/1999/xhtml";

import module namespace logx="http://cefn.com/logx" at "../lib/logx.xq";

logx:webpage(
    for $doc in $logx:collection return $doc//h1
)


Deleted link_crawler1.  Use link_crawler2 from external html module.

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

import module namespace http = "http://www.zorba-xquery.com/modules/http-client";
import module namespace file = "http://expath.org/ns/file";
import module namespace ddl = "http://www.zorba-xquery.com/modules/store/dynamic/collections/ddl";
import module namespace dml = "http://www.zorba-xquery.com/modules/store/dynamic/collections/dml";
import module namespace map = "http://www.zorba-xquery.com/modules/store/data-structures/unordered-map";
(:import module namespace lcc = "http://www.zorba-xquery.com/scripts/link-crawler-collections" at "link_crawler_collections.xq";:)
import module namespace tidy="http://www.zorba-xquery.com/modules/converters/html";
import schema namespace tidy-options="http://www.zorba-xquery.com/modules/converters/html-options";
import schema namespace httpsch = "http://expath.org/ns/http-client";
declare namespace ann = "http://www.zorba-xquery.com/annotations";
declare namespace xhtml="http://www.w3.org/1999/xhtml";
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
declare namespace err="http://www.w3.org/2005/xqt-errors";

(: declare variable $result-file as xs:string external; :)(:PROJECT_SOURCE_DIR:)

declare variable $top-uri  as xs:string := "http://www.zorba-xquery.com/site2/html/index.html"; (: the start page :)
declare variable $uri-host as xs:string := "http://www.zorba-xquery.com"; (:  what differentiates an internal uri :)

declare variable $supported-media-types as xs:string+ := ("text/xml", "application/xml", "text/xml-external-parsed-entity", "application/xml-external-parsed-entity",
                            "application/atom+xml", "text/html");

declare variable $internal-uris as xs:QName := xs:QName("internal-uris");
declare variable $external-uris as xs:QName := xs:QName("external-uris");

declare variable $broken-internal as xs:QName := xs:QName("local:broken-internal");
declare variable $broken-external as xs:QName := xs:QName("local:broken-external");
declare variable $pages-cannot-parse as xs:QName := xs:QName("local:pages-cannot-parse");

declare function local:my-substring-before($s1 as xs:string, $s2 as xs:string) as xs:string
{
  let $sb := fn:substring-before($s1, $s2)
  return
    if($sb = "") then
      $s1
    else
      $sb
};

declare %ann:sequential function local:get-uris-from-page($uri as xs:string,
                                                          $reluri as xs:string,
                                                          $call-from as xs:string)
{
  variable $method;
  if(fn:starts-with($uri, $uri-host)) then
  {
    map:insert($internal-uris, $uri, $uri);
    $method := "GET";
    fn:trace($uri, "internal ");
  }
  else
  {
    map:insert($external-uris, $uri, $uri);
    $method := "HEAD";
    fn:trace($uri, "external ");
  }

  variable $load-result;
  variable $content-string;
  try{
    $load-result := http:send-request(<httpsch:request method="{$method}" href="{$uri}"/>, (), ());
    if($load-result[1]/@status eq 200) then
      if(fn:starts-with($uri, $uri-host)) then
      {
        $content-string := string($load-result[2]);
        let $media-type := local:my-substring-before($load-result[1]/httpsch:header[@name = 'Content-Type'][1]/fn:string(@value), ";")
        return
          if($media-type = "text/html") then
            let $content := tidy:parse($content-string,
                                        <options xmlns="http://www.zorba-xquery.com/modules/converters/html-options" >
                                          <tidyParam name="output-xml" value="yes" />
                                          <tidyParam name="doctype" value="omit" />
                                          <tidyParam name="quote-nbsp" value="no" />
                                          <tidyParam name="char-encoding" value="utf8" />
                                          <tidyParam name="newline" value="LF" />
                                          <tidyParam name="tidy-mark" value="no" />
                                          <tidyParam name="new-inline-tags" value="nav header section article footer xqdoc:custom d c options json-param" />
                                        </options>)
            for $other-uri2 in  ($content//*:a/string(@href),
                                $content//*:link/string(@href),
                                $content//*:script/string(@src),
                                $content//*:img/string(@src),
                                $content//*:area/string(@href)
                               )
            let $other-uri := fn:normalize-space($other-uri2)
            let $absuri := local:my-substring-before(fn:resolve-uri($other-uri, $uri), "#")
            return
              if(fn:not(fn:starts-with($other-uri, "#")) and
                 fn:empty(map:get($internal-uris, $absuri)) and
                 fn:empty(map:get($external-uris, $absuri))) then
                local:get-uris-from-page($absuri, $other-uri, $uri);
              else (:already followed this link:)
                ();
          else(: it's binary :)
            fn:trace((" has binary content ", $media-type), "");
       }
       else(:success loading external link:)
         ();
    else (: broken link :)
      if(fn:starts-with($uri, $uri-host)) then
      {
        dml:insert-nodes-last($broken-internal, <internal-broken-uri>
                                                    <uri>{$reluri}</uri>
                                                    <call-from>{$call-from}</call-from>
                                                    <media-type>{local:my-substring-before($load-result[1]/httpsch:header[@name = 'Content-Type'][1]/fn:string(@value), ";")}</media-type>
                                                    </internal-broken-uri>);
      }
      else
      {
        dml:insert-nodes-last($broken-external, <external-broken-uri>
                                                    <uri>{$uri}</uri>
                                                    <call-from>{$call-from}</call-from>
                                                    <media-type>{local:my-substring-before($load-result[1]/httpsch:header[@name = 'Content-Type'][1]/fn:string(@value), ";")}</media-type>
                                                    </external-broken-uri>);
      }
  }catch ZXQP0003
  {
    dml:insert-nodes-last($pages-cannot-parse, <page-cannot-parse>
                                                 <uri>{$uri}</uri>
                                                 <reluri>{$reluri}</reluri>
                                                 <call-from>{$call-from}</call-from>
                                                 <err-code>{$err:code}</err-code>
                                                 <err-description>{$err:description}</err-description>
                                                 <err-value>{$err:value}</err-value>
                                                 <err-module>{$err:module}</err-module>
                                                 <err-line>{$err:line-number}</err-line>
                                                 </page-cannot-parse>);
    try{ (: tidy failed to parse the html, use regex:)
        let $content := $content-string
        let $search := fn:analyze-string($content, "(<|&lt;|<)(((a|link|area).+?href)|((script|img).+?src))=([""'])(.*?)\7")
        for $other-uri2 in  $search//fn:group[@nr=8]/fn:string()
        let $other-uri := fn:normalize-space($other-uri2)
        let $absuri := local:my-substring-before(fn:resolve-uri($other-uri, $uri), "#")
        return
          if(fn:not(fn:starts-with($other-uri, "#")) and
             fn:empty(map:get($internal-uris, $absuri)) and
             fn:empty(map:get($external-uris, $absuri))) then
            local:get-uris-from-page($absuri, $other-uri, $uri);
          else (:already followed this link:)
            ();
    }catch *
    {
      dml:insert-nodes-last($pages-cannot-parse, <page-cannot-parse>
                                                   <uri>{$uri}</uri>
                                                   <reluri>{$reluri}</reluri>
                                                   <call-from>{$call-from}</call-from>
                                                   <err-code>{$err:code}</err-code>
                                                   <err-description>{$err:description}</err-description>
                                                   <err-value>{$err:value}</err-value>
                                                   <err-module>{$err:module}</err-module>
                                                   <err-line>{$err:line-number}</err-line>
                                                   </page-cannot-parse>);
    }
  }catch *
  {
    dml:insert-nodes-last($pages-cannot-parse, <page-cannot-parse>
                                                 <uri>{$uri}</uri>
                                                 <reluri>{$reluri}</reluri>
                                                 <call-from>{$call-from}</call-from>
                                                 <err-code>{$err:code}</err-code>
                                                 <err-description>{$err:description}</err-description>
                                                 <err-value>{$err:value}</err-value>
                                                 <err-module>{$err:module}</err-module>
                                                 <err-line>{$err:line-number}</err-line>
                                                 </page-cannot-parse>);
  }
};

map:create($internal-uris, xs:QName("xs:string"));
ddl:create($broken-internal);
map:create($external-uris, xs:QName("xs:string"));
ddl:create($broken-external);
ddl:create($pages-cannot-parse);

local:get-uris-from-page($top-uri, $top-uri, "");

(:display results:)
let $full-report :=
<link-crawler website="{$top-uri}">
<internal-broken-uris>
{for $i in dml:collection($broken-internal)
let $u := $i/uri
group by $u
return $i}
</internal-broken-uris>
<pages-cannot-parse>
{for $e in dml:collection($pages-cannot-parse)
let $u := $e/uri
group by $u
return $e}
</pages-cannot-parse>
<external-uris>
{for $e in map:keys($external-uris)
let $v := $e/attribute/@value
group by $v
return <external-uri>{$e}</external-uri>}
</external-uris>
<external-broken-uris>
{for $e in dml:collection($broken-external)
let $u := $e/uri
group by $u
return  $e}
</external-broken-uris>

</link-crawler>

return
file:write(fn:resolve-uri("link_crawler_result.xml"),
            $full-report,
            <output:serialization-parameters>
                <output:indent value="yes"/>
            </output:serialization-parameters>)


Use a declared namepace for the eval options elements.

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

import module namespace sem = "http://marklogic.com/semantics" at "/MarkLogic/semantics.xqy";

declare namespace o = "http://reecedunn.co.uk/xquery/options";
declare namespace eval = "xdmp:eval";

declare option o:implementation "marklogic/6.0";

(:~ Run a query on a MarkLogic server.
 :
 : @param $mode Whether to "run", "profile", or "debug" the query.
 : @param $mimetype The mimetype of the query.
 : @param $module-path The path of the module to invoke, or "" for evaluated scripts.
 : @param $query The query script to evaluate, or "" for invoked modules.
 : @param $vars A map of the variable values by the variable name.
 : @param $types A map of the variable types by the variable name.
 : @param $context-value The context item for XSLT queries as an XML object.
 : @param $context-path The context item for XSLT queries as a module file.
 : @param $rdf-output-format The mimetype to format sem:triple results as, or "" to leave them as is.
 : @param $updating An updating query if "true", or a non-updating query if "false".
 : @param $server The name of the server to use, or "" to not use a server.
 : @param $database The name of the database to use, or "" to not use a database.
 : @param $module-root The path to the server modules, or "" to use the default server value.
 :
 : This script has additional logic to map the semantics of the REST/XCC API to
 : the semantics of the API implemented in the xquery-intellij-plugin to support
 : the Run/Debug Configurations of the IntelliJ IDEs. Specifically:
 :
 : 1.  If there is an error, the REST API returns a "500 Internal Error" HTTP
 :     status. This catches the error and returns an element(err:error) object.
 :
 : 2.  The variables are passed via the REST API as xs:untypedAtomic. This
 :     converts the variables to the type they were specified as in the
 :     xquery-intellij-plugin API.
 :
 : 3.  The REST API only returns the primitive type of each item.
 :)

declare variable $mode as xs:string external := "run";
declare variable $mimetype as xs:string external := "application/xquery";
declare variable $module-path as xs:string external := "";
declare variable $query as xs:string external := "()";
declare variable $vars as xs:string external := "{}";
declare variable $types as xs:string external := "{}";
declare variable $context-value as xs:string external := "";
declare variable $context-path as xs:string external := "";
declare variable $rdf-output-format as xs:string external := "";
declare variable $updating as xs:string external := "false";
declare variable $server as xs:string external := "";
declare variable $database as xs:string external := "";
declare variable $module-root as xs:string external := "";

declare variable $content-type-header-prefix as xs:string external := "X-Content-Type-";
declare variable $derived-type-header-prefix as xs:string external := "X-Derived-";

declare function local:nullize($value) {
    if (string-length($value) eq 0) then () else $value
};

declare function local:version() {
    substring-before(xdmp:version(), "-") cast as xs:double
};

declare function local:version-minor() {
    substring-after(xdmp:version(), "-") cast as xs:double
};

declare function local:function($ref as xs:string) {
    try { xdmp:eval($ref) } catch * { () }
};

declare function local:item($path as xs:string, $value as xs:string, $type as xs:string) {
    if (string-length($value) ne 0) then
        xdmp:unquote($value)
    else if (string-length($path) ne 0) then
        doc($path)
    else
        ()
};

declare function local:cast-as($value, $type) {
    switch ($type)
    case "xs:anyURI" return $value cast as xs:anyURI
    case "xs:base64Binary" return $value cast as xs:base64Binary
    case "xs:boolean" return $value cast as xs:boolean
    case "xs:byte" return $value cast as xs:byte
    case "xs:date" return $value cast as xs:date
    case "xs:dateTime" return $value cast as xs:dateTime
    case "xs:dateTimeStamp" return $value cast as xs:dateTime (: MarkLogic does not support XML Schema 1.1 Part 2 :)
    case "xs:dayTimeDuration" return $value cast as xs:dayTimeDuration
    case "xs:decimal" return $value cast as xs:decimal
    case "xs:double" return $value cast as xs:double
    case "xs:duration" return $value cast as xs:duration
    case "xs:float" return $value cast as xs:float
    case "xs:gDay" return $value cast as xs:gDay
    case "xs:gMonth" return $value cast as xs:gMonth
    case "xs:gMonthDay" return $value cast as xs:gMonthDay
    case "xs:gYear" return $value cast as xs:gYear
    case "xs:gYearMonth" return $value cast as xs:gYearMonth
    case "xs:hexBinary" return $value cast as xs:hexBinary
    case "xs:int" return $value cast as xs:int
    case "xs:integer" return $value cast as xs:integer
    case "xs:language" return $value cast as xs:language
    case "xs:long" return $value cast as xs:long
    case "xs:negativeInteger" return $value cast as xs:negativeInteger
    case "xs:nonNegativeInteger" return $value cast as xs:nonNegativeInteger
    case "xs:nonPositiveInteger" return $value cast as xs:nonPositiveInteger
    case "xs:normalizedString" return $value cast as xs:normalizedString
    case "xs:numeric" return $value cast as xs:numeric
    case "xs:positiveInteger" return $value cast as xs:positiveInteger
    case "xs:short" return $value cast as xs:short
    case "xs:string" return $value cast as xs:string
    case "xs:time" return $value cast as xs:time
    case "xs:token" return $value cast as xs:token
    case "xs:unsignedByte" return $value cast as xs:unsignedByte
    case "xs:unsignedInt" return $value cast as xs:unsignedInt
    case "xs:unsignedLong" return $value cast as xs:unsignedLong
    case "xs:unsignedShort" return $value cast as xs:unsignedShort
    case "xs:yearMonthDuration" return $value cast as xs:yearMonthDuration
    case "xs:ENTITY" return $value cast as xs:ENTITY
    case "xs:ID" return $value cast as xs:ID
    case "xs:IDREF" return $value cast as xs:IDREF
    case "xs:Name" return $value cast as xs:Name
    case "xs:NCName" return $value cast as xs:NCName
    case "xs:NMTOKEN" return $value cast as xs:NMTOKEN
    case "xs:QName" return $value cast as xs:QName
    default return $value
};

declare function local:parse-vars($values as map:map, $types as map:map) as item()* {
    for $key in map:keys($values)
    let $value := local:cast-as(map:get($values, $key), map:get($types, $key))
    return (xs:QName($key), $value)
};

declare function local:parse-vars-map($values as map:map, $types as map:map) as map:map {
    let $ret := map:map()
    let $_ :=
        for $key in map:keys($values)
        let $value := local:cast-as(map:get($values, $key), map:get($types, $key))
        return map:put($ret, $key, $value)
    return $ret
};

declare function local:derived-type-name($value) {
    (: NOTE: Ordering is important here -- reverse type hierarchy :)
    typeswitch ($value)
    case function(*) return "function(*)"
    (: xs:integer derived types :)
    case xs:positiveInteger return "xs:positiveInteger"
    case xs:unsignedByte return "xs:unsignedByte"
    case xs:unsignedShort return "xs:unsignedShort"
    case xs:unsignedInt return "xs:unsignedInt"
    case xs:unsignedLong return "xs:unsignedLong"
    case xs:nonNegativeInteger return "xs:nonNegativeInteger"
    case xs:byte return "xs:byte"
    case xs:short return "xs:short"
    case xs:int return "xs:int"
    case xs:long return "xs:long"
    case xs:negativeInteger return "xs:negativeInteger"
    case xs:nonPositiveInteger return "xs:nonPositiveInteger"
    (: xs:string derived types :)
    case xs:ENTITY return "xs:ENTITY"
    case xs:IDREF return "xs:IDREF"
    case xs:ID return "xs:ID"
    case xs:NCName return "xs:NCName"
    case xs:Name return "xs:Name"
    case xs:NMTOKEN return "xs:NMTOKEN"
    case xs:language return "xs:language"
    case xs:token return "xs:token"
    case xs:normalizedString return "xs:normalizedString"
    default return () (: primitive type, so does not need the type name to be specified. :)
};

declare function local:rdf-format($mimetype) {
    switch ($mimetype)
    case "application/n-quads" return "nquad"
    case "application/n-triples" return "ntriple"
    case "application/rdf+json" return "rdfjson"
    case "application/rdf+xml" return "rdfxml"
    case "application/trig" return "trig"
    case "application/vnd.marklogic.triples+xml" return "triplexml"
    case "text/n3" return "n3"
    case "text/turtle" return "turtle"
    default return fn:error("UNSUPPORTED-RDF-FORMAT", "Unsupported RDF format: " || $mimetype)
};

declare function local:use-modules-root($server-root) {
    exists($server-root) and string-length($module-root) ne 0 and not($module-root eq $server-root)
};

declare function local:eval-options() {
    let $server := local:nullize($server) ! xdmp:server(.)
    let $database :=
        let $id := local:nullize($database) ! xdmp:database(.)
        return if (exists($id)) then
            $id
        else if (exists($server)) then
            xdmp:server-database($server)
        else
            ()
    return <eval:options>{
        if ($mode eq "validate") then
            <eval:static-check>true</eval:static-check>
        else
            (),
        if (exists($database)) then
            <eval:database>{$database}</eval:database>
        else
            (),
        if (exists($server)) then
            <eval:default-collation>{xdmp:server-collation($server)}</eval:default-collation>
        else
            (),
        let $server-coordinate-system := local:function("xdmp:server-coordinate-system#1")
        return if (exists($server) and exists($server-coordinate-system)) then
            <eval:default-coordinate-system>{$server-coordinate-system($server)}</eval:default-coordinate-system>
        else
            (),
        if (exists($server) and $mimetype eq "application/xquery") then
            <eval:default-xquery-version>{xdmp:server-default-xquery-version($server)}</eval:default-xquery-version>
        else
            (),
        let $server-root := $server ! xdmp:server-root(.)
        return if (local:use-modules-root($server-root)) then
            (<eval:modules>0</eval:modules>, <eval:root>{$module-root}</eval:root>) (: file system :)
        else
            (), (: use the default server settings :)
        let $major := local:version()
        let $minor := local:version-minor()
        return if ($mode = "debug") then
            if ($updating = "true") then
                fn:error(xs:QName("err:FOER0000"), "Debugging an update query is not supported by MarkLogic.")
            else
                ()
        else if ($major lt 7.0 or ($major eq 8.0 and $minor lt 7.0) or ($major eq 9.0 and $minor lt 2.0)) then
            if ($updating = "true") then
                <eval:transaction-mode>update</eval:transaction-mode>
            else
                <eval:transaction-mode>query</eval:transaction-mode>
        else
            (: MarkLogic 8.0-7 and 9.0-2 support <update> :)
            <eval:update>{$updating}</eval:update>
    }</eval:options>
};

declare function local:javascript() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $options := local:eval-options()
    return if (local:version() < 8.0) then
        fn:error(
            xs:QName("UNSUPPORTED-VERSION"),
            "MarkLogic " || xdmp:version() || " does not support server-side JavaScript"
        )
    else if (string-length($query) ne 0) then
        switch ($mode)
        case "run" return
            let $f := local:function("xdmp:javascript-eval#3")
            let $start := xdmp:elapsed-time()
            let $ret := $f($query, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        default return ()
    else
        switch ($mode)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:invoke($module-path, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        default return ()
};

declare function local:sparql-query() as item()* {
    let $variables := local:parse-vars-map(xdmp:unquote($vars), xdmp:unquote($types))
    let $query :=
        if (string-length($query) ne 0) then
            $query
        else
            () (: TODO: Read the contents of the query file from the modules database. :)
    return switch ($mode)
    case "run" return
        let $start := xdmp:elapsed-time()
        let $ret := sem:sparql($query, $variables)
        return (xdmp:elapsed-time() - $start, $ret)
    default return ()
};

declare function local:sparql-update() as item()* {
    let $variables := local:parse-vars-map(xdmp:unquote($vars), xdmp:unquote($types))
    let $query :=
        if (string-length($query) ne 0) then
            $query
        else
            () (: TODO: Read the contents of the query file from the modules database. :)
    return if (local:version() < 8.0) then
        fn:error(
            xs:QName("UNSUPPORTED-VERSION"),
            "MarkLogic " || xdmp:version() || " does not support SPARQL update queries"
        )
    else switch ($mode)
    case "run" return
        let $start := xdmp:elapsed-time()
        let $ret := sem:sparql-update($query, $variables)
        return (xdmp:elapsed-time() - $start, $ret)
    default return ()
};

declare function local:sql() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $query :=
        if (string-length($query) ne 0) then
            $query
        else
            () (: TODO: Read the contents of the query file from the modules database. :)
    return switch ($mode)
    case "run" return
        if (local:version() < 9.0) then
            let $f := local:function("xdmp:sql#1")
            let $start := xdmp:elapsed-time()
            let $ret := $f($query)
            return (xdmp:elapsed-time() - $start, $ret)
        else
            let $f := local:function("xdmp:sql#3")
            let $start := xdmp:elapsed-time()
            let $ret := $f($query, (), $variables)
            return (xdmp:elapsed-time() - $start, $ret)
    default return ()
};

declare function local:xquery() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $options := local:eval-options()
    return if (string-length($query) ne 0) then
        switch ($mode)
        case "debug" return dbg:eval($query, $variables, $options)
        case "profile" return prof:eval($query, $variables, $options)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:eval($query, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:eval($query, $variables, $options)
        default return ()
    else
        switch ($mode)
        case "debug" return dbg:invoke($module-path, $variables, $options)
        case "profile" return prof:invoke($module-path, $variables, $options)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:invoke($module-path, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:invoke($module-path, $variables, $options)
        default return ()
};

declare function local:xslt() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $input := local:item($context-path, $context-value, "application/xml")
    let $options := local:eval-options()
    return if (string-length($query) ne 0) then
        switch ($mode)
        case "profile" return prof:xslt-eval(xdmp:unquote($query), $input, $variables, $options)
        case "run" return
            let $query := xdmp:unquote($query)
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:xslt-eval($query, $input, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:xslt-eval(xdmp:unquote($query), $input, $variables, $options)
        default return ()
    else
        switch ($mode)
        case "profile" return prof:xslt-invoke($module-path, $input, $variables, $options)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:xslt-invoke($module-path, $input, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:xslt-invoke($module-path, $input, $variables, $options)
        default return ()
};

try {
    let $retvals :=
        switch ($mimetype)
        case "application/sparql-query" return local:sparql-query()
        case "application/sparql-update" return local:sparql-update()
        case "application/sql" return local:sql()
        case "application/vnd.marklogic-javascript" return local:javascript()
        case "application/xquery" return local:xquery()
        case "application/xslt+xml" return local:xslt()
        default return ()
    let $triples := for $item in $retvals where $item instance of sem:triple return $item
    let $retvals := for $item in $retvals where not($item instance of sem:triple) return $item
    return if (exists($triples) and $rdf-output-format ne "") then
        let $rdf-output := sem:rdf-serialize($triples, local:rdf-format($rdf-output-format))
        let $_ := xdmp:add-response-header($content-type-header-prefix || (count($retvals) + 1), $rdf-output-format)
        return (
            for $retval at $i in $retvals
            let $_ := local:derived-type-name($retval) ! xdmp:add-response-header($derived-type-header-prefix || $i, .)
            return $retval,
            $rdf-output
        )
    else
        for $retval at $i in ($retvals, $triples)
        let $_ := local:derived-type-name($retval) ! xdmp:add-response-header($derived-type-header-prefix || $i, .)
        return $retval
} catch * {
    let $_ := xdmp:add-response-header($derived-type-header-prefix || 1, "err:error")
    return $err:additional
}

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

import module namespace sem = "http://marklogic.com/semantics" at "/MarkLogic/semantics.xqy";

declare namespace o = "http://reecedunn.co.uk/xquery/options";
declare option o:implementation "marklogic/6.0";

(:~ Run a query on a MarkLogic server.
 :
 : @param $mode Whether to "run", "profile", or "debug" the query.
 : @param $mimetype The mimetype of the query.
 : @param $module-path The path of the module to invoke, or "" for evaluated scripts.
 : @param $query The query script to evaluate, or "" for invoked modules.
 : @param $vars A map of the variable values by the variable name.
 : @param $types A map of the variable types by the variable name.
 : @param $context-value The context item for XSLT queries as an XML object.
 : @param $context-path The context item for XSLT queries as a module file.
 : @param $rdf-output-format The mimetype to format sem:triple results as, or "" to leave them as is.
 : @param $updating An updating query if "true", or a non-updating query if "false".
 : @param $server The name of the server to use, or "" to not use a server.
 : @param $database The name of the database to use, or "" to not use a database.
 : @param $module-root The path to the server modules, or "" to use the default server value.
 :
 : This script has additional logic to map the semantics of the REST/XCC API to
 : the semantics of the API implemented in the xquery-intellij-plugin to support
 : the Run/Debug Configurations of the IntelliJ IDEs. Specifically:
 :
 : 1.  If there is an error, the REST API returns a "500 Internal Error" HTTP
 :     status. This catches the error and returns an element(err:error) object.
 :
 : 2.  The variables are passed via the REST API as xs:untypedAtomic. This
 :     converts the variables to the type they were specified as in the
 :     xquery-intellij-plugin API.
 :
 : 3.  The REST API only returns the primitive type of each item.
 :)

declare variable $mode as xs:string external := "run";
declare variable $mimetype as xs:string external := "application/xquery";
declare variable $module-path as xs:string external := "";
declare variable $query as xs:string external := "()";
declare variable $vars as xs:string external := "{}";
declare variable $types as xs:string external := "{}";
declare variable $context-value as xs:string external := "";
declare variable $context-path as xs:string external := "";
declare variable $rdf-output-format as xs:string external := "";
declare variable $updating as xs:string external := "false";
declare variable $server as xs:string external := "";
declare variable $database as xs:string external := "";
declare variable $module-root as xs:string external := "";

declare variable $content-type-header-prefix as xs:string external := "X-Content-Type-";
declare variable $derived-type-header-prefix as xs:string external := "X-Derived-";

declare function local:nullize($value) {
    if (string-length($value) eq 0) then () else $value
};

declare function local:version() {
    substring-before(xdmp:version(), "-") cast as xs:double
};

declare function local:version-minor() {
    substring-after(xdmp:version(), "-") cast as xs:double
};

declare function local:function($ref as xs:string) {
    try { xdmp:eval($ref) } catch * { () }
};

declare function local:item($path as xs:string, $value as xs:string, $type as xs:string) {
    if (string-length($value) ne 0) then
        xdmp:unquote($value)
    else if (string-length($path) ne 0) then
        doc($path)
    else
        ()
};

declare function local:cast-as($value, $type) {
    switch ($type)
    case "xs:anyURI" return $value cast as xs:anyURI
    case "xs:base64Binary" return $value cast as xs:base64Binary
    case "xs:boolean" return $value cast as xs:boolean
    case "xs:byte" return $value cast as xs:byte
    case "xs:date" return $value cast as xs:date
    case "xs:dateTime" return $value cast as xs:dateTime
    case "xs:dateTimeStamp" return $value cast as xs:dateTime (: MarkLogic does not support XML Schema 1.1 Part 2 :)
    case "xs:dayTimeDuration" return $value cast as xs:dayTimeDuration
    case "xs:decimal" return $value cast as xs:decimal
    case "xs:double" return $value cast as xs:double
    case "xs:duration" return $value cast as xs:duration
    case "xs:float" return $value cast as xs:float
    case "xs:gDay" return $value cast as xs:gDay
    case "xs:gMonth" return $value cast as xs:gMonth
    case "xs:gMonthDay" return $value cast as xs:gMonthDay
    case "xs:gYear" return $value cast as xs:gYear
    case "xs:gYearMonth" return $value cast as xs:gYearMonth
    case "xs:hexBinary" return $value cast as xs:hexBinary
    case "xs:int" return $value cast as xs:int
    case "xs:integer" return $value cast as xs:integer
    case "xs:language" return $value cast as xs:language
    case "xs:long" return $value cast as xs:long
    case "xs:negativeInteger" return $value cast as xs:negativeInteger
    case "xs:nonNegativeInteger" return $value cast as xs:nonNegativeInteger
    case "xs:nonPositiveInteger" return $value cast as xs:nonPositiveInteger
    case "xs:normalizedString" return $value cast as xs:normalizedString
    case "xs:numeric" return $value cast as xs:numeric
    case "xs:positiveInteger" return $value cast as xs:positiveInteger
    case "xs:short" return $value cast as xs:short
    case "xs:string" return $value cast as xs:string
    case "xs:time" return $value cast as xs:time
    case "xs:token" return $value cast as xs:token
    case "xs:unsignedByte" return $value cast as xs:unsignedByte
    case "xs:unsignedInt" return $value cast as xs:unsignedInt
    case "xs:unsignedLong" return $value cast as xs:unsignedLong
    case "xs:unsignedShort" return $value cast as xs:unsignedShort
    case "xs:yearMonthDuration" return $value cast as xs:yearMonthDuration
    case "xs:ENTITY" return $value cast as xs:ENTITY
    case "xs:ID" return $value cast as xs:ID
    case "xs:IDREF" return $value cast as xs:IDREF
    case "xs:Name" return $value cast as xs:Name
    case "xs:NCName" return $value cast as xs:NCName
    case "xs:NMTOKEN" return $value cast as xs:NMTOKEN
    case "xs:QName" return $value cast as xs:QName
    default return $value
};

declare function local:parse-vars($values as map:map, $types as map:map) as item()* {
    for $key in map:keys($values)
    let $value := local:cast-as(map:get($values, $key), map:get($types, $key))
    return (xs:QName($key), $value)
};

declare function local:parse-vars-map($values as map:map, $types as map:map) as map:map {
    let $ret := map:map()
    let $_ :=
        for $key in map:keys($values)
        let $value := local:cast-as(map:get($values, $key), map:get($types, $key))
        return map:put($ret, $key, $value)
    return $ret
};

declare function local:derived-type-name($value) {
    (: NOTE: Ordering is important here -- reverse type hierarchy :)
    typeswitch ($value)
    case function(*) return "function(*)"
    (: xs:integer derived types :)
    case xs:positiveInteger return "xs:positiveInteger"
    case xs:unsignedByte return "xs:unsignedByte"
    case xs:unsignedShort return "xs:unsignedShort"
    case xs:unsignedInt return "xs:unsignedInt"
    case xs:unsignedLong return "xs:unsignedLong"
    case xs:nonNegativeInteger return "xs:nonNegativeInteger"
    case xs:byte return "xs:byte"
    case xs:short return "xs:short"
    case xs:int return "xs:int"
    case xs:long return "xs:long"
    case xs:negativeInteger return "xs:negativeInteger"
    case xs:nonPositiveInteger return "xs:nonPositiveInteger"
    (: xs:string derived types :)
    case xs:ENTITY return "xs:ENTITY"
    case xs:IDREF return "xs:IDREF"
    case xs:ID return "xs:ID"
    case xs:NCName return "xs:NCName"
    case xs:Name return "xs:Name"
    case xs:NMTOKEN return "xs:NMTOKEN"
    case xs:language return "xs:language"
    case xs:token return "xs:token"
    case xs:normalizedString return "xs:normalizedString"
    default return () (: primitive type, so does not need the type name to be specified. :)
};

declare function local:rdf-format($mimetype) {
    switch ($mimetype)
    case "application/n-quads" return "nquad"
    case "application/n-triples" return "ntriple"
    case "application/rdf+json" return "rdfjson"
    case "application/rdf+xml" return "rdfxml"
    case "application/trig" return "trig"
    case "application/vnd.marklogic.triples+xml" return "triplexml"
    case "text/n3" return "n3"
    case "text/turtle" return "turtle"
    default return fn:error("UNSUPPORTED-RDF-FORMAT", "Unsupported RDF format: " || $mimetype)
};

declare function local:use-modules-root($server-root) {
    exists($server-root) and string-length($module-root) ne 0 and not($module-root eq $server-root)
};

declare function local:eval-options() {
    let $server := local:nullize($server) ! xdmp:server(.)
    let $database :=
        let $id := local:nullize($database) ! xdmp:database(.)
        return if (exists($id)) then
            $id
        else if (exists($server)) then
            xdmp:server-database($server)
        else
            ()
    return <options xmlns="xdmp:eval">{
        if ($mode eq "validate") then
            <static-check>true</static-check>
        else
            (),
        if (exists($database)) then
            <database>{$database}</database>
        else
            (),
        if (exists($server)) then
            <default-collation>{xdmp:server-collation($server)}</default-collation>
        else
            (),
        let $server-coordinate-system := local:function("xdmp:server-coordinate-system#1")
        return if (exists($server) and exists($server-coordinate-system)) then
            <default-coordinate-system>{$server-coordinate-system($server)}</default-coordinate-system>
        else
            (),
        if (exists($server) and $mimetype eq "application/xquery") then
            <default-xquery-version>{xdmp:server-default-xquery-version($server)}</default-xquery-version>
        else
            (),
        let $server-root := $server ! xdmp:server-root(.)
        return if (local:use-modules-root($server-root)) then
            (<modules>0</modules>, <root>{$module-root}</root>) (: file system :)
        else
            (), (: use the default server settings :)
        let $major := local:version()
        let $minor := local:version-minor()
        return if ($mode = "debug") then
            if ($updating = "true") then
                fn:error(xs:QName("err:FOER0000"), "Debugging an update query is not supported by MarkLogic.")
            else
                ()
        else if ($major lt 7.0 or ($major eq 8.0 and $minor lt 7.0) or ($major eq 9.0 and $minor lt 2.0)) then
            if ($updating = "true") then
                <transaction-mode>update</transaction-mode>
            else
                <transaction-mode>query</transaction-mode>
        else
            (: MarkLogic 8.0-7 and 9.0-2 support <update> :)
            <update>{$updating}</update>
    }</options>
};

declare function local:javascript() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $options := local:eval-options()
    return if (local:version() < 8.0) then
        fn:error(
            xs:QName("UNSUPPORTED-VERSION"),
            "MarkLogic " || xdmp:version() || " does not support server-side JavaScript"
        )
    else if (string-length($query) ne 0) then
        switch ($mode)
        case "run" return
            let $f := local:function("xdmp:javascript-eval#3")
            let $start := xdmp:elapsed-time()
            let $ret := $f($query, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        default return ()
    else
        switch ($mode)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:invoke($module-path, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        default return ()
};

declare function local:sparql-query() as item()* {
    let $variables := local:parse-vars-map(xdmp:unquote($vars), xdmp:unquote($types))
    let $query :=
        if (string-length($query) ne 0) then
            $query
        else
            () (: TODO: Read the contents of the query file from the modules database. :)
    return switch ($mode)
    case "run" return
        let $start := xdmp:elapsed-time()
        let $ret := sem:sparql($query, $variables)
        return (xdmp:elapsed-time() - $start, $ret)
    default return ()
};

declare function local:sparql-update() as item()* {
    let $variables := local:parse-vars-map(xdmp:unquote($vars), xdmp:unquote($types))
    let $query :=
        if (string-length($query) ne 0) then
            $query
        else
            () (: TODO: Read the contents of the query file from the modules database. :)
    return if (local:version() < 8.0) then
        fn:error(
            xs:QName("UNSUPPORTED-VERSION"),
            "MarkLogic " || xdmp:version() || " does not support SPARQL update queries"
        )
    else switch ($mode)
    case "run" return
        let $start := xdmp:elapsed-time()
        let $ret := sem:sparql-update($query, $variables)
        return (xdmp:elapsed-time() - $start, $ret)
    default return ()
};

declare function local:sql() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $query :=
        if (string-length($query) ne 0) then
            $query
        else
            () (: TODO: Read the contents of the query file from the modules database. :)
    return switch ($mode)
    case "run" return
        if (local:version() < 9.0) then
            let $f := local:function("xdmp:sql#1")
            let $start := xdmp:elapsed-time()
            let $ret := $f($query)
            return (xdmp:elapsed-time() - $start, $ret)
        else
            let $f := local:function("xdmp:sql#3")
            let $start := xdmp:elapsed-time()
            let $ret := $f($query, (), $variables)
            return (xdmp:elapsed-time() - $start, $ret)
    default return ()
};

declare function local:xquery() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $options := local:eval-options()
    return if (string-length($query) ne 0) then
        switch ($mode)
        case "debug" return dbg:eval($query, $variables, $options)
        case "profile" return prof:eval($query, $variables, $options)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:eval($query, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:eval($query, $variables, $options)
        default return ()
    else
        switch ($mode)
        case "debug" return dbg:invoke($module-path, $variables, $options)
        case "profile" return prof:invoke($module-path, $variables, $options)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:invoke($module-path, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:invoke($module-path, $variables, $options)
        default return ()
};

declare function local:xslt() as item()* {
    let $variables := local:parse-vars(xdmp:unquote($vars), xdmp:unquote($types))
    let $input := local:item($context-path, $context-value, "application/xml")
    let $options := local:eval-options()
    return if (string-length($query) ne 0) then
        switch ($mode)
        case "profile" return prof:xslt-eval(xdmp:unquote($query), $input, $variables, $options)
        case "run" return
            let $query := xdmp:unquote($query)
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:xslt-eval($query, $input, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:xslt-eval(xdmp:unquote($query), $input, $variables, $options)
        default return ()
    else
        switch ($mode)
        case "profile" return prof:xslt-invoke($module-path, $input, $variables, $options)
        case "run" return
            let $start := xdmp:elapsed-time()
            let $ret := xdmp:xslt-invoke($module-path, $input, $variables, $options)
            return (xdmp:elapsed-time() - $start, $ret)
        case "validate" return xdmp:xslt-invoke($module-path, $input, $variables, $options)
        default return ()
};

try {
    let $retvals :=
        switch ($mimetype)
        case "application/sparql-query" return local:sparql-query()
        case "application/sparql-update" return local:sparql-update()
        case "application/sql" return local:sql()
        case "application/vnd.marklogic-javascript" return local:javascript()
        case "application/xquery" return local:xquery()
        case "application/xslt+xml" return local:xslt()
        default return ()
    let $triples := for $item in $retvals where $item instance of sem:triple return $item
    let $retvals := for $item in $retvals where not($item instance of sem:triple) return $item
    return if (exists($triples) and $rdf-output-format ne "") then
        let $rdf-output := sem:rdf-serialize($triples, local:rdf-format($rdf-output-format))
        let $_ := xdmp:add-response-header($content-type-header-prefix || (count($retvals) + 1), $rdf-output-format)
        return (
            for $retval at $i in $retvals
            let $_ := local:derived-type-name($retval) ! xdmp:add-response-header($derived-type-header-prefix || $i, .)
            return $retval,
            $rdf-output
        )
    else
        for $retval at $i in ($retvals, $triples)
        let $_ := local:derived-type-name($retval) ! xdmp:add-response-header($derived-type-header-prefix || $i, .)
        return $retval
} catch * {
    let $_ := xdmp:add-response-header($derived-type-header-prefix || 1, "err:error")
    return $err:additional
}