[testsuite] XQuery test suite: test element now accepts an attribute ignore="yes" to temporarily disable a test. Port of rev 13962.

git-svn-id: 1623499149f5af833cfad2814dce82e821210f6f@13963 8784284e-840f-0410-bd5a-a6a6012a0d1a

xquery version "1.0";

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

import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace xdiff="http://exist-db.org/xquery/xmldiff"
at "java:org.exist.xquery.modules.xmldiff.XmlDiffModule";

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

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

declare function t:store-files($action as element(store-files)) {
    let $type := if ($action/@type) then $action/@type/string() else "application/xml"
    return
        xdb:store-files-from-pattern($action/@collection, $action/@dir, $action/@pattern, $type)
};

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

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

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

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

declare function t:test($result as item()*) {
    if ($result instance of xs:boolean) then
        $result
    else
        exists($result)
};

declare function t:run-test($test as element(test), $count as xs:integer) {
	let $context := t:init-prolog($test)
	let $null :=
	   if ($test/@trace eq 'yes') then
	       (system:clear-trace(), system:enable-tracing(true(), false()))
       else ()
    let $highlight-option := concat("highlight-matches=",
          if ($test/expected//@*[matches(., '^(\|{3}).*\1$')] and $test/expected//exist:match) then "both"
          else if ($test/expected//@*[matches(., '^(\|{3}).*\1$')]) then "attributes"
          else if ($test/expected//exist:match) then "elements"
          else "none"
          )
    let $serialize-options :=
      let $decls := ($test/../*[name() ne 'test']|$test/code)[matches(., 'declare[\- ]option(\(("|')|\s+)exist:serialize(\2,)?\s+("|').*?\4[;)]')]
      let $ops1 := $decls/replace(., "declare[\- ]option(\(("|')|\s+)exist:serialize(\2,)?\s+("|')(.*?)\4[;)]", "_|$5_")
      let $ops2 :=
        for $a in $ops1
        for $b in tokenize($a, '_')[starts-with(., '|')]
        return tokenize(substring-after($b, '|'), '\s+')
      return if (count($ops2[matches(., 'highlight-matches')]))
        then string-join($ops2, ' ')
        else string-join(($ops2, $highlight-option), ' ')
    let $queryOutput :=
		util:catch("*",
			util:eval(concat($context, $test/code/string())),
			<error>Compilation error: {$util:exception-message}</error>
		)
	let $output := if ($test/@trace eq 'yes') then system:trace() else $queryOutput
    let $expanded :=
		if ($output instance of node()) then
        	util:expand($output, $serialize-options)
		else
			$output
    let $expected :=
        if ($test/@output eq 'text') then
            data($test/expected)
        else $test/expected/node()
    let $OK :=
        if ($test/xpath) then
            t:test(t:xpath($output, $test/xpath))
        else if ($test/@output eq 'text') then
            normalize-space(string-join(for $x in $output return string($x),' ')) eq normalize-space($expected)
        else
            let $xn := t:normalize($expanded)
            let $en := t:normalize($expected)
            return
        	   deep-equal($xn, $en)
    return
        <test n="{$count}" pass="{$OK}">
        {
            if (not($OK)) then
                ($test/task, $test/expected, <result>{$expanded}</result>)
            else
                ()
        }
        </test>
};

declare function t:normalize($nodes as node()*) {
	for $node in $nodes return t:normalize-node($node)
};

declare function t:normalize-node($node as node()) {
	typeswitch ($node)
		case element() return
			element { node-name($node) } {
				$node/@*, for $child in $node/node() return t:normalize-node($child)
			}
		case text() return
			let $norm := normalize-space($node)
			return
				if (string-length($norm) eq 0) then () else $node
		default return
			$node
};

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

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

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

{$result/testName}

{$result/description/p}

          {for $test in $result//test
           return

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

          }

     return
        $formatted
};

xquery version "1.0";

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

import module namespace xdb="http://exist-db.org/xquery/xmldb";
import module namespace xdiff="http://exist-db.org/xquery/xmldiff"
at "java:org.exist.xquery.modules.xmldiff.XmlDiffModule";

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

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

declare function t:store-files($action as element(store-files)) {
    let $type := if ($action/@type) then $action/@type/string() else "application/xml"
    return
        xdb:store-files-from-pattern($action/@collection, $action/@dir, $action/@pattern, $type)
};

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

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

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

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

declare function t:test($result as item()*) {
    if ($result instance of xs:boolean) then
        $result
    else
        exists($result)
};

declare function t:run-test($test as element(test), $count as xs:integer) {
	let $context := t:init-prolog($test)
	let $null :=
	   if ($test/@trace eq 'yes') then
	       (system:clear-trace(), system:enable-tracing(true(), false()))
       else ()
    let $highlight-option := concat("highlight-matches=",
          if ($test/expected//@*[matches(., '^(\|{3}).*\1$')] and $test/expected//exist:match) then "both"
          else if ($test/expected//@*[matches(., '^(\|{3}).*\1$')]) then "attributes"
          else if ($test/expected//exist:match) then "elements"
          else "none"
          )
    let $serialize-options :=
      let $decls := ($test/../*[name() ne 'test']|$test/code)[matches(., 'declare[\- ]option(\(("|')|\s+)exist:serialize(\2,)?\s+("|').*?\4[;)]')]
      let $ops1 := $decls/replace(., "declare[\- ]option(\(("|')|\s+)exist:serialize(\2,)?\s+("|')(.*?)\4[;)]", "_|$5_")
      let $ops2 :=
        for $a in $ops1
        for $b in tokenize($a, '_')[starts-with(., '|')]
        return tokenize(substring-after($b, '|'), '\s+')
      return if (count($ops2[matches(., 'highlight-matches')]))
        then string-join($ops2, ' ')
        else string-join(($ops2, $highlight-option), ' ')
    let $queryOutput :=
		util:catch("*",
			util:eval(concat($context, $test/code/string())),
			<error>Compilation error: {$util:exception-message}</error>
		)
	let $output := if ($test/@trace eq 'yes') then system:trace() else $queryOutput
    let $expanded :=
		if ($output instance of node()) then
        	util:expand($output, $serialize-options)
		else
			$output
    let $expected :=
        if ($test/@output eq 'text') then
            data($test/expected)
        else $test/expected/node()
    let $OK :=
        if ($test/xpath) then
            t:test(t:xpath($output, $test/xpath))
        else if ($test/@output eq 'text') then
            normalize-space(string-join(for $x in $output return string($x),' ')) eq normalize-space($expected)
        else
            let $xn := t:normalize($expanded)
            let $en := t:normalize($expected)
            return
        	   deep-equal($xn, $en)
    return
        <test n="{$count}" pass="{$OK}">
        {
            if (not($OK)) then
                ($test/task, $test/expected, <result>{$expanded}</result>)
            else
                ()
        }
        </test>
};

declare function t:normalize($nodes as node()*) {
	for $node in $nodes return t:normalize-node($node)
};

declare function t:normalize-node($node as node()) {
	typeswitch ($node)
		case element() return
			element { node-name($node) } {
				$node/@*, for $child in $node/node() return t:normalize-node($child)
			}
		case text() return
			let $norm := normalize-space($node)
			return
				if (string-length($norm) eq 0) then () else $node
		default return
			$node
};

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

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

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

{$result/testName}

{$result/description/p}

          {for $test in $result//test
           return

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

          }

     return
        $formatted
};


[ignore] Fixed broken articles page.

[ignore] Fixed broken articles page.

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

xquery version "1.0";

declare namespace mods="http://www.loc.gov/mods/v3";
declare namespace mads="http://www.loc.gov/mads/";
declare namespace xlink="http://www.w3.org/1999/xlink";
declare namespace fo="http://www.w3.org/1999/XSL/Format";

declare option exist:serialize "media-type=text/xml";

declare variable $mods:MODS_COLLECTION := "/db/mods/eXist";

declare function mods:add-part($part, $sep as xs:string) {
    if (empty($part) or string-length($part[1]) eq 0) then
        ()
    else
        concat(string-join($part, " "), $sep)
};

declare function mods:get-extent($extent as element(mods:extent)) {
    if ($extent/mods:end) then
        concat($extent/mods:start, " - ", $extent/mods:end)
    else
        $extent/mods:start
};

declare function mods:get-part-and-origin($entry as element()) {
    let $part := $entry/mods:part
    let $origin := $entry/mods:originInfo
    return (
        mods:add-part($origin/mods:place/mods:placeTerm, ": "),
        mods:add-part($origin/mods:publisher, ", "),
        ($origin/mods:dateIssued/string(), $part/mods:date/string(),
        $origin/mods:dateCreated/string())[1]
    )
};

declare function mods:get-conference($entry as element(mods:mods)) {
    let $date := ($entry/mods:originInfo/mods:dateIssued/string(), $entry/mods:part/mods:date/string(),
            $entry/mods:originInfo/mods:dateCreated/string())[1]
    return
        concat("Paper presented at ",
            mods:add-part($entry/mods:name[@type = 'conference']/mods:namePart, ", "),
            mods:add-part($entry/mods:originInfo/mods:place/mods:placeTerm, ", "),
            $date
        )
};

declare function mods:get-name($name as element(mods:name), $pos as xs:integer) {
	if ($name/@type = 'corporate') then
        $name/mods:namePart[@lang]
	else
		let $family := $name/mods:namePart[@type = 'family']
		let $given := $name/mods:namePart[@type = 'given']
		return
			if ($family and $given) then
				if ($pos eq 1) then
				    concat($family/text(), ', ', $given/text())
				else
					concat($given/text(), ' ', $family/text())
		  else
		      $name/text()
};

declare function mods:get-names($entry as element()) {
    let $names :=
        for $name at $pos in $entry/mods:name[@type = ('personal', 'corporate')]
        return
            mods:get-name($name, $pos)
    let $nameCount := count($names)
    let $formatted :=
        if ($nameCount eq 0) then
            ()
        else if ($nameCount eq 1) then
            concat($names[1], '. ')
        else
            concat(
                string-join(subsequence($names, 1, $nameCount - 1), ", "),
                ", and ",
                $names[$nameCount],
                ". "
            )
    return
        $formatted
};

declare function mods:get-title($entry as element()) {
    let $title := $entry/mods:titleInfo
    return
        if ($entry//mods:url) then

            { $title/mods:title/string() }.

        else
            <emphasis>
            { $title/mods:title/string() }.
            </emphasis>
};

declare function mods:get-related($entry as element(mods:mods)) {
    let $related := $entry/mods:relatedItem[@type = 'host']
    return
        if ($related) then
            concat(
                "In:",
                mods:get-names($related), mods:get-title($related),
                if ($related/mods:originInfo or $related/mods:part) then
                    mods:get-part-and-origin($related)
                else if ($related/mods:location/mods:url) then
                    concat(", ", $related/mods:location/mods:url)
                else
                    ()
            )
        else
            ()
};

declare function mods:process($entry as element(mods:mods)) {
    <para>
    {
        mods:get-names($entry),
        mods:get-title($entry),
        if ($entry/mods:name[@type = 'conference']) then
            mods:get-conference($entry)
        else (
            mods:get-part-and-origin($entry),
            mods:get-related($entry)
        ),
        if ($entry/mods:location/mods:url[@displayLabel]) then
             ({$entry/mods:location/mods:url/@displayLabel/string()})
        else ()
      }
    </para>
};

declare function mods:list-articles() {
    for $entry in collection($mods:MODS_COLLECTION)//mods:mods
    let $date := ($entry/mods:originInfo/mods:dateIssued/string(), $entry/mods:part/mods:date/string(),
            $entry/mods:originInfo/mods:dateCreated/string())[1]
    order by $date descending
    return
        mods:process($entry)
};

<book>
    <bookinfo>
        <graphic fileref="logo.jpg"/>

        <productname>Open Source Native XML Database</productname>
        <title>Articles on eXist</title>
        <link rel="shortcut icon" href="../resources/exist_icon_16x16.ico"/>
		<link rel="icon" href="../resources/exist_icon_16x16.png" type="image/png"/>
    </bookinfo>

    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="sidebar.xml"/>

    <chapter>
        <title>Articles on eXist</title>

        {
            if (empty(collection($mods:MODS_COLLECTION)//mods:mods)) then
                <para>Article references are contained in a MODS document which will be installed
                    with the other sample documents. Please go to the
                    <ulink url="admin/admin.xql">admin interface</ulink> and launch
                    "Examples Setup".</para>
            else
                <para>A collection of articles, blog posts, tutorials and papers which mention eXist. They
                may help to get started or provide information on special features. The references can
                also be queried/sorted via the "<ulink url="cocoon/biblio.xq">Bibliographic</ulink>"
                demo.</para>
        }

        { mods:list-articles() }
    </chapter>
</book>

xquery version "1.0";

declare namespace mods="http://www.loc.gov/mods/v3";
declare namespace mads="http://www.loc.gov/mads/";
declare namespace xlink="http://www.w3.org/1999/xlink";
declare namespace fo="http://www.w3.org/1999/XSL/Format";

declare option exist:serialize "media-type=text/xml";

declare function mods:add-part($part, $sep as xs:string) {
    if (empty($part) or string-length($part[1]) eq 0) then
        ()
    else
        concat(string-join($part, " "), $sep)
};

declare function mods:get-extent($extent as element(mods:extent)) {
    if ($extent/mods:end) then
        concat($extent/mods:start, " - ", $extent/mods:end)
    else
        $extent/mods:start
};

declare function mods:get-part-and-origin($entry as element()) {
    let $part := $entry/mods:part
    let $origin := $entry/mods:originInfo
    return (
        mods:add-part($origin/mods:place/mods:placeTerm, ": "),
        mods:add-part($origin/mods:publisher, ", "),
        ($origin/mods:dateIssued/string(), $part/mods:date/string(),
        $origin/mods:dateCreated/string())[1]
    )
};

declare function mods:get-conference($entry as element(mods:mods)) {
    let $date := ($entry/mods:originInfo/mods:dateIssued/string(), $entry/mods:part/mods:date/string(),
            $entry/mods:originInfo/mods:dateCreated/string())[1]
    return
        concat("Paper presented at ",
            mods:add-part($entry/mods:name[@type = 'conference']/mods:namePart, ", "),
            mods:add-part($entry/mods:originInfo/mods:place/mods:placeTerm, ", "),
            $date
        )
};

declare function mods:get-name($name as element(mods:name), $pos as xs:integer) {
	if ($name/@type = 'corporate') then
        $name/mods:namePart[@lang]
	else
		let $family := $name/mods:namePart[@type = 'family']
		let $given := $name/mods:namePart[@type = 'given']
		return
			if ($family and $given) then
				if ($pos eq 1) then
				    concat($family/text(), ', ', $given/text())
				else
					concat($given/text(), ' ', $family/text())
		  else
		      $name/text()
};

declare function mods:get-names($entry as element()) {
    let $names :=
        for $name at $pos in $entry/mods:name[@type = ('personal', 'corporate')]
        return
            mods:get-name($name, $pos)
    let $nameCount := count($names)
    let $formatted :=
        if ($nameCount eq 0) then
            ()
        else if ($nameCount eq 1) then
            concat($names[1], '. ')
        else
            concat(
                string-join(subsequence($names, 1, $nameCount - 1), ", "),
                ", and ",
                $names[$nameCount],
                ". "
            )
    return
        $formatted
};

declare function mods:get-title($entry as element()) {
    let $title := $entry/mods:titleInfo
    return
        if ($entry//mods:url) then

            { $title/mods:title/string() }.

        else
            <emphasis>
            { $title/mods:title/string() }.
            </emphasis>
};

declare function mods:get-related($entry as element(mods:mods)) {
    let $related := $entry/mods:relatedItem[@type = 'host']
    return
        if ($related) then
            concat(
                "In:",
                mods:get-names($related), mods:get-title($related),
                if ($related/mods:originInfo or $related/mods:part) then
                    mods:get-part-and-origin($related)
                else if ($related/mods:location/mods:url) then
                    concat(", ", $related/mods:location/mods:url)
                else
                    ()
            )
        else
            ()
};

declare function mods:process($entry as element(mods:mods)) {
    <para>
    {
        mods:get-names($entry),
        mods:get-title($entry),
        if ($entry/mods:name[@type = 'conference']) then
            mods:get-conference($entry)
        else (
            mods:get-part-and-origin($entry),
            mods:get-related($entry)
        ),
        if ($entry/mods:location/mods:url[@displayLabel]) then
             ({$entry/mods:location/mods:url/@displayLabel/string()})
        else ()
      }
    </para>
};

declare function mods:list-articles() {
    for $entry in /mods:modsCollection/mods:mods
    let $date := ($entry/mods:originInfo/mods:dateIssued/string(), $entry/mods:part/mods:date/string(),
            $entry/mods:originInfo/mods:dateCreated/string())[1]
    order by $date descending
    return
        mods:process($entry)
};

<book>
    <bookinfo>
        <graphic fileref="logo.jpg"/>

        <productname>Open Source Native XML Database</productname>
        <title>Articles on eXist</title>
        <link rel="shortcut icon" href="../resources/exist_icon_16x16.ico"/>
		<link rel="icon" href="../resources/exist_icon_16x16.png" type="image/png"/>
    </bookinfo>

    <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="sidebar.xml"/>

    <chapter>
        <title>Articles on eXist</title>

        {
            if (empty(/mods:mods)) then
                <para>Article references are contained in a MODS document which will be installed
                    with the other sample documents. Please go to the
                    <ulink url="admin/admin.xql">admin interface</ulink> and launch
                    "Examples Setup".</para>
            else
                <para>A collection of articles, blog posts, tutorials and papers which mention eXist. They
                may help to get started or provide information on special features. The references can
                also be queried/sorted via the "<ulink url="cocoon/biblio.xq">Bibliographic</ulink>"
                demo.</para>
        }

        { mods:list-articles() }
    </chapter>
</book>


Removing unneeded Socrates dependency

Removing unneeded Socrates dependency

(:
 :	Copyright 2008-2010 Mark Logic Corporation
 :
 :	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.
 :
 :	@author Justin Makeig <jmakeig@marklogic.com>
 :
 :)
xquery version "1.0-ml";
import module namespace r="http://marklogic.com/router" at "/Socrates/src/lib/router.xqy";
declare option xdmp:mapping "false";

let $url as xs:string := xdmp:get-request-url()
let $method as xs:string := xdmp:get-request-method()
let $accept as xs:string? := xdmp:get-request-header("Accept")
let $options as element(r:routes) := r:read-routes("/routes.xml")
return
	r:route($options, $url, $method, $accept)

(:
 :	Copyright 2008-2010 Mark Logic Corporation
 :
 :	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.
 :
 :	@author Justin Makeig <jmakeig@marklogic.com>
 :
 :)
xquery version "1.0-ml";
import module namespace r="http://marklogic.com/router" at "/Socrates/src/lib/router.xqy";
import module namespace s="http://marklogic.com/socrates" at "lib/socrates.xqy";
declare option xdmp:mapping "false";

let $url as xs:string := xdmp:get-request-url()
let $method as xs:string := xdmp:get-request-method()
let $accept as xs:string? := xdmp:get-request-header("Accept")
let $options as element(r:routes) := r:read-routes("/routes.xml")
return
	r:route($options, $url, $method, $accept)


Added pragma, xqts has too much results since watchdog has been enabled again

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

declare option exist:serialize "method=xml indent=yes";
declare option exist:output-size-limit "-1";
<test-suite-result>

        <implementation name="{util:system-property("product-version")}" version="{util:system-property("product-build")}" anonymous-result-column="false">

                <organization name="eXist Open Source native XML database"  website="http://www.exist-db.org" anonymous="false"/>

                <submittor name="eXist XQTS testsuite runner" email="me@not.com"/>

                <description>

eXist is an Open Source native XML database featuring efficient,
                        index-based XQuery processing, automatic indexing, extensions for full-text
                        search,  XUpdate  support and tight integration with existing XML development tools.

                </description>

                <implementation-defined-items>

                </implementation-defined-items>

                <features>
{ for $feature in doc('/db/XQTS/XQTSCatalog.xml')/*:test-suite/*:features/*:feature
							return
							<feature name="{$feature/@name}" supported="true"/>
						}</features>

                <context-properties>

                </context-properties>

        </implementation>

        <syntax>XQuery</syntax>

        <test-run dateRun="{fn:current-dateTime()}">
                <test-suite version="{doc('/db/XQTS/XQTSCatalog.xml')/*:test-suite/@version}"/>
                <transformation>

No unusual transformations.

                </transformation>
                <comparison>

No unusual comparisons

                </comparison>
                <otherComments>

The test run took n seconds.

                </otherComments>
        </test-run>

{
    for $case in fn:collection(  '/db/XQTS' )//test-case
    return <test-case name="{$case/@name}" result="{$case/@result}"  />
}
</test-suite-result>

declare option exist:serialize "method=xml indent=yes";
<test-suite-result>

        <implementation name="{util:system-property("product-version")}" version="{util:system-property("product-build")}" anonymous-result-column="false">

                <organization name="eXist Open Source native XML database"  website="http://www.exist-db.org" anonymous="false"/>

                <submittor name="eXist XQTS testsuite runner" email="me@not.com"/>

                <description>

eXist is an Open Source native XML database featuring efficient,
                        index-based XQuery processing, automatic indexing, extensions for full-text
                        search,  XUpdate  support and tight integration with existing XML development tools.

                </description>

                <implementation-defined-items>

                </implementation-defined-items>

                <features>
{ for $feature in doc('/db/XQTS/XQTSCatalog.xml')/*:test-suite/*:features/*:feature
							return
							<feature name="{$feature/@name}" supported="true"/>
						}</features>

                <context-properties>

                </context-properties>

        </implementation>

        <syntax>XQuery</syntax>

        <test-run dateRun="{fn:current-dateTime()}">
                <test-suite version="{doc('/db/XQTS/XQTSCatalog.xml')/*:test-suite/@version}"/>
                <transformation>

No unusual transformations.

                </transformation>
                <comparison>

No unusual comparisons

                </comparison>
                <otherComments>

The test run took n seconds.

                </otherComments>
        </test-run>

{
    for $case in fn:collection(  '/db/XQTS' )//test-case
    return <test-case name="{$case/@name}" result="{$case/@result}"  />
}
</test-suite-result>


The category names do not include numbers to indicate the level in the hierarchy.

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

import module namespace xqdg = "http://www.zorba-xquery.com/modules/internal/xqdoc-xhtml" at "xqdoc-xhtml.xq";

import schema namespace xqdoc = "http://www.xqdoc.org/1.0" at "xqdoc-1.0.xsd";

declare copy-namespaces preserve, inherit;

(:~
 : This variable contains the relative paths to directories that contain
 : example code fragments that are included.
 :)
declare variable $examplePath as xs:string* := (
    'test/rbkt/Queries/zorba',
    'test/update/Queries',
    'test/rbkt/ExpQueryResults/zorba',
    'test/update/ExpectedTestResults'
);

(:~
 : This variable contains categories in the left menu
 :)
declare variable $leftMenu :=
<menu>
  <category name="http://expath.org/ns" uri="http://expath.org/ns" />
  <category name="http://www.zorba-xquery.com/modules" uri="http://www.zorba-xquery.com/modules">
    <category name="email" uri="http://www.zorba-xquery.com/modules/email" />
    <category name="excel" uri="http://www.zorba-xquery.com/modules/excel" />
    <category name="image" uri="http://www.zorba-xquery.com/modules/image" />
    <category name="introspection" uri="http://www.zorba-xquery.com/modules/introspection" />
    <category name="security" uri="http://www.zorba-xquery.com/modules/security" />
    <category name="oauth" uri="http://www.zorba-xquery.com/modules/oauth" />
    <category name="webservices" uri="http://www.zorba-xquery.com/modules/webservices" last="true">
      <category name="google" uri="http://www.zorba-xquery.com/modules/webservices/google" />
      <category name="yahoo" uri="http://www.zorba-xquery.com/modules/webservices/yahoo" last="true" />
    </category>
  </category>
  <category name="http://www.w3.org/2005" uri="http://www.w3.org/2005" last="true"/>
</menu>;

declare variable $menu :=
XQuery Libraries
;

declare variable $table :=
;

(:~
 : This variable contains the modules directory path in the source directory.
 :)
declare variable $modulesPath as xs:string external;

(:~
 : This variable contains the path where to generate the XQDoc.
 :)
declare variable $xqdocBuildPath as xs:string external;

(:~
 : This variable points to where the generated XML must be saved.
 :)
declare variable $xqdocXmlPath as xs:string := fn:concat($xqdocBuildPath, file:path-separator(), "xml");

(:~
 : This variable points to where the generated XHTML must be saved.
 :)
declare variable $xqdocXhtmlPath as xs:string := fn:concat($xqdocBuildPath, file:path-separator(), "xhtml");

declare variable $stepBacks as xs:string := "../../../../../../../../../../../../../../../../../../../../";

(:~
 : This variable contains the to the index.html main page
 :)
declare variable $indexHtmlPath as xs:string external;

declare variable $indexCollector := <modules/>;

declare function local:getFileName($moduleURI as xs:string) as xs:string
{
    replace(
        replace($moduleURI, "/", "_"),
        "http:__",
        ""
    )
};

declare sequential function local:clearFolder($folderPath as xs:string, $pattern as xs:string) as xs:string*
{
  if(fn:not(file:exists($folderPath))) then
    return
  else
    for $file in file:files($folderPath, $pattern, fn:true())
    let $filePath := fn:concat($folderPath, file:path-separator(), $file)
    return
      try {
        file:remove($filePath);
        concat("
  SUCCESS: ", $filePath);
      } catch * ($error_code) {
        concat("
  FAILED: ", $filePath)
      }
};

(:~
 : This function generates the XQDoc XML for all the modules found in $modulesPath
 : and writes the resulting XML documents in $targetPath. The hierarchy is preserved.
 :
 : @param $modulePath where to search for modules recursively.
 : @param $targetPath where to generate the XQDoc XML documents.
 : @return The function returns a string sequence with a status messge for each
 :         module processed.
 :)
declare sequential function local:generateXQDocXml() as xs:string*
{
  for $filedirs in tokenize($modulesPath, ";")
  for $file in file:files($filedirs, "\.xq$", fn:true())
  let $filePath := fn:concat($filedirs, file:path-separator(), $file)
  let $xqdoc := xqd:xqdoc(file:path-to-uri($filePath))
  let $moduleDoc := $xqdoc/xqdoc:module
  let $moduleName := $moduleDoc/xqdoc:name
  let $moduleUri := $moduleDoc/xqdoc:uri
  return
    try {
      file:mkdirs($xqdocXmlPath, false());
      let $x := fn:count(file:files($xqdocXmlPath, "\.xml$", fn:true())) + 1
      let $xqdocFileName := fn:concat($xqdocXmlPath, file:path-separator(), local:getFileName($moduleUri), ".xml")
      return
      file:write($xqdocFileName, $xqdoc, <s method="xml" indent="yes" />/@*);
      concat("
SUCCESS: ", $moduleUri, " (", ()(:$xqdocFileName:), ")");
    } catch * ($error_code) {
      concat("
FAILED: ", $moduleUri, " (", ()(:$xqdocFileName:), ")")
    }
};

(:~
 : This function removes the internal functionality from an XQDoc XML node.
 :
 : @param $xqdoc The XQDdoc XML node to remove the functionality from.
 : @return The xqdoc node without the internal functionality.
 :)
declare sequential function local:removeInternalFunctionality($xqdoc as node()) as node() {
  delete node $xqdoc/xqdoc:functions/xqdoc:function[fn:starts-with(fn:data(xqdoc:comment/xqdoc:description), "Helper function")];
  $xqdoc;
};

(:~
 : This function generates the XQDoc XHTML pages for all the XQDoc XML
 : documents found in $xqdocPath and writes the resulting pages to in
 : $targetPath. The hierarchy is preserved.
 :
 : @param $indexPath path to the XHTML index page.
 :)
declare sequential function local:generateXQDocXhtml($indexPath as xs:string) as xs:string*
{
  let $indexHtmlDoc := file:read-xml($indexPath)
  return
  for $file in file:files($xqdocXmlPath, "\.xml$", fn:true())
  let $stepsFromIndex := fn:count(fn:tokenize($file, fn:concat("\", file:path-separator()))) - 2
  let $xmlFilePath := concat($xqdocXmlPath, file:path-separator(), $file)
  let $xhtmlFilePath := concat($xqdocXhtmlPath, file:path-separator(), fn:replace($file, "\.xml$", ".html"))
  let $xhtmlFileDir :=
    let $segments := fn:tokenize($xhtmlFilePath, fn:concat("\", file:path-separator()))
    let $lastSegm := $segments[fn:count($segments)]
    return fn:substring-before($xhtmlFilePath, $lastSegm)
  return
    try {
      let $xqdoc := local:removeInternalFunctionality(file:read-xml($xmlFilePath)/xqdoc:xqdoc)
      let $moduleDoc := $xqdoc/xqdoc:module
      let $moduleName := $moduleDoc/xqdoc:name
      let $moduleUri := $moduleDoc/xqdoc:uri
      let $menu :=
XQuery Libraries

      let $menu := local:createLeftMenu($menu, $moduleUri, $leftMenu)
      let $xhtml := xqdg:doc($xqdoc, $menu)
      return block {
        file:mkdirs($xhtmlFileDir, false());

        local:configure-xhtml($xhtml, $stepsFromIndex);

        file:write($xhtmlFilePath, $xhtml, <s method="xhtml" indent="yes" />/@*);

        concat("
SUCCESS: ", $moduleUri, " (", $xhtmlFilePath, ")");
      }
    } catch * ($error_code) {
      concat("
FAILED: ", $xhtmlFilePath)
    }
};

(:~
 : This function gathers the names of the XQDoc XHTML pages for all the XQDoc XML
 : documents found in $xqdocXmlPath. The hierarchy is preserved.
 :)
declare sequential function local:gatherModules()
{
  for $file in file:files($xqdocXmlPath, "\.xml$", fn:true())
  let $xmlFilePath := concat($xqdocXmlPath, file:path-separator(), $file)
  let $xhtmlRelativeFilePath := fn:replace($file, "\.xml$", ".html")
  let $xhtmlRelativeFilePathSlash := fn:replace($xhtmlRelativeFilePath, fn:concat("\", file:path-separator()), "/")
  return
  try {
      let $xqdoc := local:removeInternalFunctionality(file:read-xml($xmlFilePath)/xqdoc:xqdoc)
      let $moduleDoc := $xqdoc/xqdoc:module
      let $moduleUri := $moduleDoc/xqdoc:uri
      return block {
        local:collectModule($moduleDoc, $xhtmlRelativeFilePath);
        concat("
SUCCESS: ", $moduleUri, " (", $xmlFilePath, ")");
      }
    } catch * ($error_code) {
      concat("
FAILED: ", $xmlFilePath)
    }
};

declare sequential function local:collectModule ($module, $relativeFileName as xs:string) {
    let $moduleName := $module/xqdoc:name,
        $moduleUri := $module/xqdoc:uri
    return
        insert node <module uri="{$moduleUri/text()}" file="{$relativeFileName}" /> as last into $indexCollector;
    ();
};

(:~
 : This function returns the left menu needed in the index.html and also all the XHTML module pages.
 :
 :)
declare sequential function local:createLeftMenu($menu, $moduleUri, $categories)
{
  for $cat1 in $categories/category
  let $last1 := if(fn:exists($cat1/@last)) then fn:boolean(fn:data($cat1/@last)) else fn:false()
  return block {
    local:createCategory($menu, $moduleUri, $cat1, $last1);
    for $cat2 in $cat1/category
    let $last2 := if(fn:exists($cat2/@last)) then fn:boolean(fn:data($cat2/@last)) else fn:false()
    let $menu2 := $menu/li[fn:last()]/ul
    return block {
      local:createCategory($menu2, $moduleUri, $cat2, $last2);
      for $cat3 in $cat2/category
      let $last3 := if(fn:exists($cat3/@last)) then fn:boolean(fn:data($cat3/@last)) else fn:false()
      let $menu3 := $menu/li[fn:last()]/ul/li[fn:last()]/ul
      return block {
        local:createCategory($menu3, $moduleUri, $cat3, $last3);
      };
    };
  };

  $menu;

};

(:~
 : This is a helper function used to add a category and the modules belonging to it to a node in the menu
 :
 : @param $menu the node in the menu where the new category will be added as the last node
 : @param $moduleUri the name of this module will be highlighted in red as this is the current selected item in the menu
 : @param $category the node in the $leftMenu variable that will be added to the $menu
 : @param $last bool indicating if this is the last item in the $menu node needed in order to set the treeview control
 :)
declare sequential function local:createCategory($menu, $moduleUri, $category, $last as xs:boolean)
{
  block {
  if($last) then
    insert nodes

{' '}

    {data($category/@name)}

    {
     for $module in $indexCollector/module
      order by fn:data($module/@uri)
      return block {
        if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
           and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
           and fn:not($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
                and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
                and ($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else ()
        };
    }

    as last into $menu
  else
    insert nodes

{' '}

    {data($category/@name)}

    {
      for $module in $indexCollector/module
      order by fn:data($module/@uri)
      return block {
        if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
           and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
           and fn:not($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
                and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
                and ($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else ()
        };
    }

    as last into $menu
    };

   $menu;
};

declare sequential function local:getFilePath ($filename as xs:string) as xs:string*
{
  let $zorbaPath := replace($modulesPath,"/modules","")
  for $relPath in $examplePath
  let $path := concat($zorbaPath,'/',$relPath)
  let $test := file:files($path,concat("^",$filename,"$"),fn:true())[1]
  return
  if (fn:exists($test)) then
    $test
  else
    ()
};

declare function local:get-path-to-index ($stepsBack) as xs:string
{
  fn:substring($stepBacks, 1, 3 * $stepsBack)
};

declare sequential function local:configure-xhtml ($xhtml, $stepsFromIndex as xs:integer)
{
  let $pathToIndex := local:get-path-to-index($stepsFromIndex)
  return
  (: replace the <test> nodes with eiter links to the actual files or inline the actual files based on the 'type' attribute value :)
  for $file in $xhtml//*:include
  let $type := $file/@type
  let $path := local:getFilePath($file/text())
  let $read_text := file:read-text($path)
  return block {
  (: at the moment there is no way to ship the files defined as links with the packages/installers
    if (matches($type, "link")) then
      replace node $file with {$path}
    else :)
    if (matches($type, "inline")) then
      replace node $file with
        if (fn:exists($path)) then

 {$path}:

{$read_text}

        else

No example matching pattern '{$file/text()}' was found. Please update 'examplePath' variable.

        else ()
  };

  (: replace the function type description with images :)
  let $xquSpec := "http://www.w3.org/TR/xquery-update-10/",
      $xqsSpec := "http://www.w3.org/TR/xquery-sx-10/#dt-sequential-function",
      $xq11Spec := "http://www.w3.org/TR/xquery-11/#FunctionDeclns"
  let $pathToIndex := local:get-path-to-index($stepsFromIndex)
  let $imagesPath := concat($pathToIndex, "images/")
  for $typeTd in $xhtml//*:td
  where $typeTd/@class eq "type"
  let $type := $typeTd/text()
  return block {
    if (matches($type, "updating")) then
      replace node $typeTd/text() with

    else if (matches($type, "sequential")) then
      replace node $typeTd/text() with

    else if (matches($type, "nondeterministic")) then
      replace node $typeTd/text() with

    else ();
  };

  $xhtml;
};

declare sequential function local:createModuleTable() {
  for $cat1 in $leftMenu/category
  return block {
    local:createModuleHelper($table, $cat1);
    for $cat2 in $cat1/category
    let $table2 := $table/li[fn:last()]/ul
    return block {
      local:createModuleHelper($table2, $cat2);
      for $cat3 in $cat2/category
      let $table3 := $table/li[fn:last()]/ul/li[fn:last()]/ul
      return block {
        local:createModuleHelper($table3, $cat3);
      };
    };
  };

  $table;
};

declare sequential function local:createModuleHelper($table, $category)
{
  block {
    insert nodes
{data($category/@name)}

    {
     for $module in $indexCollector/module
      order by fn:data($module/@uri)
      return
        if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
           and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else ()
    }

    as last into $table
    };

   $table;
};

(:~
 : This function reads, updates and returns the new index.html.
 :
 : @param $indexPath Where to search for XML XQDoc documents recursively.
 : @return The content of the new index.html.
 :)
declare sequential function local:generateIndexHtml($indexPath as xs:string, $menu, $modules) as document-node() {
    let $indexHtmlDoc := file:read-xml($indexPath)
    return block {
        insert nodes $menu
        as last into $indexHtmlDoc/*:html/*:body/*:div[@id='main']/*:div[@id='leftMenu'];

        let $module_list := $indexHtmlDoc/*:html/*:body/*:div[@id='main']/*:div[@id='rightcontent']/*:div[@id='module_list']
        return
          if ($module_list)
          then
            insert node $modules as last into $module_list
          else
            ();

        $indexHtmlDoc;
    }
};

(: generate the XQDoc XML for all the modules :)
if (file:mkdirs($xqdocXmlPath, false())) then
(
  local:clearFolder($xqdocXmlPath,"\.xml$"),
  local:generateXQDocXml()
)
else
  error()
;

(: generate the XQDoc XHTML for all the modules :)
let $absoluteXhtmlDir := concat($xqdocBuildPath, "/xhtml")
return
if (file:mkdirs($absoluteXhtmlDir, false())) then
(
  local:clearFolder($xqdocXhtmlPath,"xqdoc\.html$"),
  local:gatherModules(),
  local:generateXQDocXhtml($indexHtmlPath)
)
else
  error()
;

let $menu :=

               XQuery Libraries

let $menu := local:createLeftMenu($menu, "index.html", $leftMenu)
let $modules := local:createModuleTable()
let $doc := local:generateIndexHtml($indexHtmlPath, $menu, $modules)
return local:configure-xhtml($doc/*:html, 0)
;

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

import module namespace xqdg = "http://www.zorba-xquery.com/modules/internal/xqdoc-xhtml" at "xqdoc-xhtml.xq";

import schema namespace xqdoc = "http://www.xqdoc.org/1.0" at "xqdoc-1.0.xsd";

declare copy-namespaces preserve, inherit;

(:~
 : This variable contains the relative paths to directories that contain
 : example code fragments that are included.
 :)
declare variable $examplePath as xs:string* := (
    'test/rbkt/Queries/zorba',
    'test/update/Queries',
    'test/rbkt/ExpQueryResults/zorba',
    'test/update/ExpectedTestResults'
);

(:~
 : This variable contains categories in the left menu
 :)
declare variable $leftMenu :=
<menu>
  <category1 name="http://expath.org/ns" uri="http://expath.org/ns" />
  <category1 name="http://www.zorba-xquery.com/modules" uri="http://www.zorba-xquery.com/modules">
    <category2 name="email" uri="http://www.zorba-xquery.com/modules/email" />
    <category2 name="excel" uri="http://www.zorba-xquery.com/modules/excel" />
    <category2 name="image" uri="http://www.zorba-xquery.com/modules/image" />
    <category2 name="introspection" uri="http://www.zorba-xquery.com/modules/introspection" />
    <category2 name="security" uri="http://www.zorba-xquery.com/modules/security" />
    <category2 name="oauth" uri="http://www.zorba-xquery.com/modules/oauth" />
    <category2 name="webservices" uri="http://www.zorba-xquery.com/modules/webservices" last="true">
      <category3 name="google" uri="http://www.zorba-xquery.com/modules/webservices/google" />
      <category3 name="yahoo" uri="http://www.zorba-xquery.com/modules/webservices/yahoo" last="true" />
    </category2>
  </category1>
  <category1 name="http://www.w3.org/2005" uri="http://www.w3.org/2005" last="true"/>
</menu>;

declare variable $menu :=
XQuery Libraries
;

declare variable $table :=
;

(:~
 : This variable contains the modules directory path in the source directory.
 :)
declare variable $modulesPath as xs:string external;

(:~
 : This variable contains the path where to generate the XQDoc.
 :)
declare variable $xqdocBuildPath as xs:string external;

(:~
 : This variable points to where the generated XML must be saved.
 :)
declare variable $xqdocXmlPath as xs:string := fn:concat($xqdocBuildPath, file:path-separator(), "xml");

(:~
 : This variable points to where the generated XHTML must be saved.
 :)
declare variable $xqdocXhtmlPath as xs:string := fn:concat($xqdocBuildPath, file:path-separator(), "xhtml");

declare variable $stepBacks as xs:string := "../../../../../../../../../../../../../../../../../../../../";

(:~
 : This variable contains the to the index.html main page
 :)
declare variable $indexHtmlPath as xs:string external;

declare variable $indexCollector := <modules/>;

declare function local:getFileName($moduleURI as xs:string) as xs:string
{
    replace(
        replace($moduleURI, "/", "_"),
        "http:__",
        ""
    )
};

declare sequential function local:clearFolder($folderPath as xs:string, $pattern as xs:string) as xs:string*
{
  if(fn:not(file:exists($folderPath))) then
    return
  else
    for $file in file:files($folderPath, $pattern, fn:true())
    let $filePath := fn:concat($folderPath, file:path-separator(), $file)
    return
      try {
        file:remove($filePath);
        concat("
  SUCCESS: ", $filePath);
      } catch * ($error_code) {
        concat("
  FAILED: ", $filePath)
      }
};

(:~
 : This function generates the XQDoc XML for all the modules found in $modulesPath
 : and writes the resulting XML documents in $targetPath. The hierarchy is preserved.
 :
 : @param $modulePath where to search for modules recursively.
 : @param $targetPath where to generate the XQDoc XML documents.
 : @return The function returns a string sequence with a status messge for each
 :         module processed.
 :)
declare sequential function local:generateXQDocXml() as xs:string*
{
  for $filedirs in tokenize($modulesPath, ";")
  for $file in file:files($filedirs, "\.xq$", fn:true())
  let $filePath := fn:concat($filedirs, file:path-separator(), $file)
  let $xqdoc := xqd:xqdoc(file:path-to-uri($filePath))
  let $moduleDoc := $xqdoc/xqdoc:module
  let $moduleName := $moduleDoc/xqdoc:name
  let $moduleUri := $moduleDoc/xqdoc:uri
  return
    try {
      file:mkdirs($xqdocXmlPath, false());
      let $x := fn:count(file:files($xqdocXmlPath, "\.xml$", fn:true())) + 1
      let $xqdocFileName := fn:concat($xqdocXmlPath, file:path-separator(), local:getFileName($moduleUri), ".xml")
      return
      file:write($xqdocFileName, $xqdoc, <s method="xml" indent="yes" />/@*);
      concat("
SUCCESS: ", $moduleUri, " (", ()(:$xqdocFileName:), ")");
    } catch * ($error_code) {
      concat("
FAILED: ", $moduleUri, " (", ()(:$xqdocFileName:), ")")
    }
};

(:~
 : This function removes the internal functionality from an XQDoc XML node.
 :
 : @param $xqdoc The XQDdoc XML node to remove the functionality from.
 : @return The xqdoc node without the internal functionality.
 :)
declare sequential function local:removeInternalFunctionality($xqdoc as node()) as node() {
  delete node $xqdoc/xqdoc:functions/xqdoc:function[fn:starts-with(fn:data(xqdoc:comment/xqdoc:description), "Helper function")];
  $xqdoc;
};

(:~
 : This function generates the XQDoc XHTML pages for all the XQDoc XML
 : documents found in $xqdocPath and writes the resulting pages to in
 : $targetPath. The hierarchy is preserved.
 :
 : @param $indexPath path to the XHTML index page.
 :)
declare sequential function local:generateXQDocXhtml($indexPath as xs:string) as xs:string*
{
  let $indexHtmlDoc := file:read-xml($indexPath)
  return
  for $file in file:files($xqdocXmlPath, "\.xml$", fn:true())
  let $stepsFromIndex := fn:count(fn:tokenize($file, fn:concat("\", file:path-separator()))) - 2
  let $xmlFilePath := concat($xqdocXmlPath, file:path-separator(), $file)
  let $xhtmlFilePath := concat($xqdocXhtmlPath, file:path-separator(), fn:replace($file, "\.xml$", ".html"))
  let $xhtmlFileDir :=
    let $segments := fn:tokenize($xhtmlFilePath, fn:concat("\", file:path-separator()))
    let $lastSegm := $segments[fn:count($segments)]
    return fn:substring-before($xhtmlFilePath, $lastSegm)
  return
    try {
      let $xqdoc := local:removeInternalFunctionality(file:read-xml($xmlFilePath)/xqdoc:xqdoc)
      let $moduleDoc := $xqdoc/xqdoc:module
      let $moduleName := $moduleDoc/xqdoc:name
      let $moduleUri := $moduleDoc/xqdoc:uri
      let $menu :=
XQuery Libraries

      let $menu := local:createLeftMenu($menu, $moduleUri, $leftMenu)
      let $xhtml := xqdg:doc($xqdoc, $menu)
      return block {
        file:mkdirs($xhtmlFileDir, false());

        local:configure-xhtml($xhtml, $stepsFromIndex);

        file:write($xhtmlFilePath, $xhtml, <s method="xhtml" indent="yes" />/@*);

        concat("
SUCCESS: ", $moduleUri, " (", $xhtmlFilePath, ")");
      }
    } catch * ($error_code) {
      concat("
FAILED: ", $xhtmlFilePath)
    }
};

(:~
 : This function gathers the names of the XQDoc XHTML pages for all the XQDoc XML
 : documents found in $xqdocXmlPath. The hierarchy is preserved.
 :)
declare sequential function local:gatherModules()
{
  for $file in file:files($xqdocXmlPath, "\.xml$", fn:true())
  let $xmlFilePath := concat($xqdocXmlPath, file:path-separator(), $file)
  let $xhtmlRelativeFilePath := fn:replace($file, "\.xml$", ".html")
  let $xhtmlRelativeFilePathSlash := fn:replace($xhtmlRelativeFilePath, fn:concat("\", file:path-separator()), "/")
  return
  try {
      let $xqdoc := local:removeInternalFunctionality(file:read-xml($xmlFilePath)/xqdoc:xqdoc)
      let $moduleDoc := $xqdoc/xqdoc:module
      let $moduleUri := $moduleDoc/xqdoc:uri
      return block {
        local:collectModule($moduleDoc, $xhtmlRelativeFilePath);
        concat("
SUCCESS: ", $moduleUri, " (", $xmlFilePath, ")");
      }
    } catch * ($error_code) {
      concat("
FAILED: ", $xmlFilePath)
    }
};

declare sequential function local:collectModule ($module, $relativeFileName as xs:string) {
    let $moduleName := $module/xqdoc:name,
        $moduleUri := $module/xqdoc:uri
    return
        insert node <module uri="{$moduleUri/text()}" file="{$relativeFileName}" /> as last into $indexCollector;
    ();
};

(:~
 : This function returns the left menu needed in the index.html and also all the XHTML module pages.
 :
 :)
declare sequential function local:createLeftMenu($menu, $moduleUri, $categories)
{
  for $cat1 in $categories/category1
  let $last1 := if(fn:exists($cat1/@last)) then fn:boolean(fn:data($cat1/@last)) else fn:false()
  return block {
    local:createCategory($menu, $moduleUri, $cat1, $last1);
    for $cat2 in $cat1/category2
    let $last2 := if(fn:exists($cat2/@last)) then fn:boolean(fn:data($cat2/@last)) else fn:false()
    let $menu2 := $menu/li[fn:last()]/ul
    return block {
      local:createCategory($menu2, $moduleUri, $cat2, $last2);
      for $cat3 in $cat2/category3
      let $last3 := if(fn:exists($cat3/@last)) then fn:boolean(fn:data($cat3/@last)) else fn:false()
      let $menu3 := $menu/li[fn:last()]/ul/li[fn:last()]/ul
      return block {
        local:createCategory($menu3, $moduleUri, $cat3, $last3);
      };
    };
  };

  $menu;

};

(:~
 : This is a helper function used to add a category and the modules belonging to it to a node in the menu
 :
 : @param $menu the node in the menu where the new category will be added as the last node
 : @param $moduleUri the name of this module will be highlighted in red as this is the current selected item in the menu
 : @param $category the node in the $leftMenu variable that will be added to the $menu
 : @param $last bool indicating if this is the last item in the $menu node needed in order to set the treeview control
 :)
declare sequential function local:createCategory($menu, $moduleUri, $category, $last as xs:boolean)
{
  block {
  if($last) then
    insert nodes

{' '}

    {data($category/@name)}

    {
     for $module in $indexCollector/module
      order by fn:data($module/@uri)
      return block {
        if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
           and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
           and fn:not($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
                and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
                and ($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else ()
        };
    }

    as last into $menu
  else
    insert nodes

{' '}

    {data($category/@name)}

    {
      for $module in $indexCollector/module
      order by fn:data($module/@uri)
      return block {
        if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
           and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
           and fn:not($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
                and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))
                and ($module/@uri = $moduleUri)) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else ()
        };
    }

    as last into $menu
    };

   $menu;
};

declare sequential function local:getFilePath ($filename as xs:string) as xs:string*
{
  let $zorbaPath := replace($modulesPath,"/modules","")
  for $relPath in $examplePath
  let $path := concat($zorbaPath,'/',$relPath)
  let $test := file:files($path,concat("^",$filename,"$"),fn:true())[1]
  return
  if (fn:exists($test)) then
    $test
  else
    ()
};

declare function local:get-path-to-index ($stepsBack) as xs:string
{
  fn:substring($stepBacks, 1, 3 * $stepsBack)
};

declare sequential function local:configure-xhtml ($xhtml, $stepsFromIndex as xs:integer)
{
  let $pathToIndex := local:get-path-to-index($stepsFromIndex)
  return
  (: replace the <test> nodes with eiter links to the actual files or inline the actual files based on the 'type' attribute value :)
  for $file in $xhtml//*:include
  let $type := $file/@type
  let $path := local:getFilePath($file/text())
  let $read_text := file:read-text($path)
  return block {
  (: at the moment there is no way to ship the files defined as links with the packages/installers
    if (matches($type, "link")) then
      replace node $file with {$path}
    else :)
    if (matches($type, "inline")) then
      replace node $file with
        if (fn:exists($path)) then

 {$path}:

{$read_text}

        else

No example matching pattern '{$file/text()}' was found. Please update 'examplePath' variable.

        else ()
  };

  (: replace the function type description with images :)
  let $xquSpec := "http://www.w3.org/TR/xquery-update-10/",
      $xqsSpec := "http://www.w3.org/TR/xquery-sx-10/#dt-sequential-function",
      $xq11Spec := "http://www.w3.org/TR/xquery-11/#FunctionDeclns"
  let $pathToIndex := local:get-path-to-index($stepsFromIndex)
  let $imagesPath := concat($pathToIndex, "images/")
  for $typeTd in $xhtml//*:td
  where $typeTd/@class eq "type"
  let $type := $typeTd/text()
  return block {
    if (matches($type, "updating")) then
      replace node $typeTd/text() with

    else if (matches($type, "sequential")) then
      replace node $typeTd/text() with

    else if (matches($type, "nondeterministic")) then
      replace node $typeTd/text() with

    else ();
  };

  $xhtml;
};

declare sequential function local:createModuleTable() {
  for $cat1 in $leftMenu/category1
  return block {
    local:createModuleHelper($table, $cat1);
    for $cat2 in $cat1/category2
    let $table2 := $table/li[fn:last()]/ul
    return block {
      local:createModuleHelper($table2, $cat2);
      for $cat3 in $cat2/category3
      let $table3 := $table/li[fn:last()]/ul/li[fn:last()]/ul
      return block {
        local:createModuleHelper($table3, $cat3);
      };
    };
  };

  $table;
};

declare sequential function local:createModuleHelper($table, $category)
{
  block {
    insert nodes
{data($category/@name)}

    {
     for $module in $indexCollector/module
      order by fn:data($module/@uri)
      return
        if(fn:starts-with(fn:string($module/@uri),data($category/@uri))
           and fn:not(fn:contains (fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/')),'/'))) then

{fn:substring-after(data($module/@uri),fn:concat(data($category/@uri),'/'))}

        else ()
    }

    as last into $table
    };

   $table;
};

(:~
 : This function reads, updates and returns the new index.html.
 :
 : @param $indexPath Where to search for XML XQDoc documents recursively.
 : @return The content of the new index.html.
 :)
declare sequential function local:generateIndexHtml($indexPath as xs:string, $menu, $modules) as document-node() {
    let $indexHtmlDoc := file:read-xml($indexPath)
    return block {
        insert nodes $menu
        as last into $indexHtmlDoc/*:html/*:body/*:div[@id='main']/*:div[@id='leftMenu'];

        let $module_list := $indexHtmlDoc/*:html/*:body/*:div[@id='main']/*:div[@id='rightcontent']/*:div[@id='module_list']
        return
          if ($module_list)
          then
            insert node $modules as last into $module_list
          else
            ();

        $indexHtmlDoc;
    }
};

(: generate the XQDoc XML for all the modules :)
if (file:mkdirs($xqdocXmlPath, false())) then
(
  local:clearFolder($xqdocXmlPath,"\.xml$"),
  local:generateXQDocXml()
)
else
  error()
;

(: generate the XQDoc XHTML for all the modules :)
let $absoluteXhtmlDir := concat($xqdocBuildPath, "/xhtml")
return
if (file:mkdirs($absoluteXhtmlDir, false())) then
(
  local:clearFolder($xqdocXhtmlPath,"xqdoc\.html$"),
  local:gatherModules(),
  local:generateXQDocXhtml($indexHtmlPath)
)
else
  error()
;

let $menu :=

               XQuery Libraries

let $menu := local:createLeftMenu($menu, "index.html", $leftMenu)
let $modules := local:createModuleTable()
let $doc := local:generateIndexHtml($indexHtmlPath, $menu, $modules)
return local:configure-xhtml($doc/*:html, 0)
;