[MarkLogic] Remove JavaScript documentation from parameter descriptions.

(:
 : Copyright (C) 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 "3.1";

declare namespace apidoc = "http://marklogic.com/xdmp/apidoc";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace xhtml = "http://www.w3.org/1999/xhtml";

declare variable $marklogic-version as xs:string external;

declare variable $language as xs:string external := "xquery"; (: xquery | javascript | rest :)
declare variable $namespace as xs:string external;
declare variable $local-name as xs:string external;

declare variable $apidoc as element(apidoc:apidoc) :=
    typeswitch (.)
    case xs:string return fn:parse-xml(.)/element()
    case document-node() return ./element()
    default return .;

(: documentation helpers --------------------------------------------------- :)

declare function local:apidoc-language($doc as element()) as xs:string {
    ($doc/@class, "xquery")[1]
};

declare function local:prefix($namespaces as map(*), $namespace as xs:string) as xs:string {
    for $prefix in map:keys($namespaces)
    where map:get($namespaces, $prefix) = $namespace
    return $prefix
};

declare function local:documentation-html($doc as node()) as node()* {
    if ($doc/namespace-uri() = "http://marklogic.com/xdmp/apidoc") then
        let $first :=
            let $node := $doc/node()[position() = 1]
            return if ($node instance of text() and string-length($node/normalize-space()) != 0) then
                ()
            else
                $node
        return if (exists($first) and (some $child in $doc/node() satisfies $child instance of element())) then
            if (local:apidoc-language($doc) = $language) then
                for $child in $doc/node()
                return local:documentation-html($child)
            else ()
        else

{$doc/node()}

    else if ($doc instance of text()) then
        let $text := $doc/normalize-space()
        return if ($text != "") then
            $doc
        else ()
    else if ($doc instance of element() and local:apidoc-language($doc) = $language) then
        element { $doc/local-name() } {
            for $child in $doc/node()
            return local:documentation-html($child)
        }
    else ()
};

(: namespaces -------------------------------------------------------------- :)

declare variable $module-namespaces := map:merge(
    for $import in $apidoc//apidoc:module/apidoc:summary//(*:p|*:pre)
    let $match := fn:analyze-string(($import/*:code, $import)[1], "import module (namespace\s*([a-z0-9]+)\s*=\s*)?""([^""]+)""")/fn:match[1]
    let $prefix := $import/ancestor::apidoc:module/@lib
    let $namespace := $match/fn:group[@nr = "3"]/string()
    where exists($namespace)
    return map:entry($prefix, $namespace)
);

declare variable $xquery-namespaces := map {
    "local": "http://www.w3.org/2005/xquery-local-functions",
    "fn": "http://www.w3.org/2005/xpath-functions",
    "xml": "http://www.w3.org/XML/1998/namespace",
    "xs": "http://www.w3.org/2001/XMLSchema",
    "xsi": "http://www.w3.org/2001/XMLSchema-instance"
};

declare variable $marklogic-5-builtin := map {
    "cts": "http://marklogic.com/cts",
    "dbg": "http://marklogic.com/xdmp/dbg",
    "dir": "http://marklogic.com/xdmp/directory",
    "error": "http://marklogic.com/xdmp/error",
    "map": "http://marklogic.com/xdmp/map",
    "math": "http://marklogic.com/xdmp/math",
    "prof": "http://marklogic.com/xdmp/profile",
    "sec": "http://marklogic.com/security",
    "spell": "http://marklogic.com/xdmp/spell",
    "xdmp": "http://marklogic.com/xdmp"
};

declare variable $marklogic-6-builtin := map {
    "err": "http://www.w3.org/2005/xqt-error"
};

declare variable $marklogic-7-builtin := map {
    "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
    "sc": "http://marklogic.com/xdmp/schema-components",
    "sql": "http://marklogic.com/xdmp/sql"
};

declare variable $marklogic-10-builtin := map {
    "cntk": "http://marklogic.com/cntk",
    "ort": "http://marklogic.com/onnxruntime"
};

declare variable $marklogic-additional := map {
    "as": "http://marklogic.com/xdmp/assignments",
    "db": "http://marklogic.com/xdmp/database",
    "dg": "xdmp:document-get",
    "cl": "http://marklogic.com/xdmp/clusters",
    "exsl": "http://exslt.org/common",
    "extusr": "http://marklogic.com/xdmp/external/user",
    "gr": "http://marklogic.com/xdmp/group",
    "lang": "http://marklogic.com/xdmp/language",
    "list": "http://marklogic.com/manage/package/list",
    "md": "urn:oasis:names:tc:SAML:2.0:metadata",
    "mt": "http://marklogic.com/xdmp/mimetypes",
    "pkg": "http://marklogic.com/manage/package",
    "s": "http://www.w3.org/2009/xpath-functions/analyze-string",
    "sch": "http://purl.oclc.org/dsdl/schematron",
    "x509": "http://marklogic.com/xdmp/x509",
    "xdt": "http://www.w3.org/2004/10/xpath-datatypes",
    "xi": "http://www.w3.org/2001/XInclude"
};

declare variable $namespaces := map:merge((
    $module-namespaces,
    $xquery-namespaces,
    $marklogic-5-builtin,
    $marklogic-6-builtin,
    $marklogic-7-builtin,
    $marklogic-10-builtin,
    $marklogic-additional,
    ()
));

(: functions --------------------------------------------------------------- :)

(: Several functions in the apidocs have duplicate parameter names in some versions, so fix these. :)
declare variable $param-fixes := map {
    "fn:subtract-dateTimes-yielding-dayTimeDuration": ("srcval1", "srcval2"),
    "fn:subtract-dateTimes-yielding-yearMonthDuration": ("srcval1", "srcval2"),
    "geo:region-contains": ("target", "region", "options"),
    "math:fmod": ("x", "y"),
    "math:rank": ("arg1", "arg2", "options")
};

declare variable $functions as element(apidoc:function)* := $apidoc//apidoc:function[
    local:function-language(.) = $language and not(@name = "")
];

declare function local:function-uri($function as element(apidoc:function)) as xs:string {
    ``[http://docs.marklogic.com/`{$marklogic-version}`/`{local:function-name($function)}`]``
};

declare function local:function-language($function as element(apidoc:function)) as xs:string {
    let $bucket := $function/@bucket
    return switch ($bucket)
    case "REST Resources API" return "rest"
    default return local:apidoc-language($function)
};

declare function local:function-name($function as element(apidoc:function)) as xs:string {
    ``[`{$function/@lib}`:`{$function/@name}`]``
};

declare function local:function-parameters($function as element(apidoc:function)) as xs:string* {
    let $names as xs:string* :=
        let $names := map:get($param-fixes, local:function-name($function))
        return if (exists($names)) then
            $names
        else
            $function/apidoc:params/apidoc:param[local:apidoc-language(.) = $language]/@name/string()
    return if (count($names) != count(distinct-values($names))) then
        fn:error(xs:QName("err:XQST0039"),``[Duplicate parameter name in `{local:function-name($function)}`]``)
    else
        $names
};

declare function local:function-arity($function as element(apidoc:function)) as map(*) {
    let $params := $function/apidoc:params/apidoc:param[local:apidoc-language(.) = $language]
    return map {
        "min": count($params[not(@optional = "true")]),
        "max": count($params)
    }
};

declare function local:function-parameter($function as element(apidoc:function), $name as xs:string) as element(apidoc:param) {
    let $names := map:get($param-fixes, local:function-name($function))
    return if (exists($names)) then
        let $i := fn:index-of($names, $name)
        return $function/apidoc:params/apidoc:param[$i]
    else
        $function/apidoc:params/apidoc:param[@name = $name and local:apidoc-language(.) = $language]
};

declare function local:function-parameter-type($function as element(apidoc:function), $name as xs:string) as xs:string {
    let $type := local:function-parameter($function, $name)/@type/string()
    return switch ($type)
    case "atomic type" return "item()*"
    case "xs:string)" return "xs:string"
    case "xs:dateTime? | xs:date? | xs:string?" return "(xs:dateTime?|xs:date?|xs:string?)"
    case "binary())" return "binary()"
    case "element(sec:query-rolesets)*)" return "element(sec:query-rolesets)*"
    case "function()" return "function(*)"
    case "item()* | map:map" return "(item()*|map:map)"
    case "(binary()|node())*" return "(binary()*|node()*)"
    case "(binary()|node())?" return "(binary()?|node()?)"
    case "(element()|map:map)?" case "element()?|map:map?" return "(element()?|map:map?)"
    case "(node()? | map:map)?" return "(node()?|map:map?)"
    case "(cts:order|xs:string)*" return "(cts:order*|xs:string*)"
    case "[xs:string?]" return "xs:string?"
    default return replace($type, ",\.\.\.", "...")
};

declare function local:function-return-type($function as element(apidoc:function)) as xs:string {
    let $type := normalize-space($function/apidoc:return[local:apidoc-language(.) = $language])
    return switch ($type)
    case "An XML representation of the certificate." return "element()?"
    case "element())" case "Element()" return "element()"
    case "element()|map:map" return "(element()|map:map)"
    case "element(xsd:schema)*" return "element(xs:schema)*"
    case "empty-sequence" case "empty sequence" return "empty-sequence()"
    case "xs:string)" return "xs:string"
    case "xs:unsignedLong)" return "xs:unsignedLong"
    case "pkgins:install($pkgname)" return "element(pkg:install-status)"
    case "pkgins:revert($ticket)" return "element(pkg:revert-status)"
    case "query-results-serialize($results)" return "item()*"
    case "The return data type is the data type of the date argument" return "item()"
    case "" return
        switch (local:function-name($function))
        case "admin:appserver-set-output-indent-tabs" return "element(configuration)"
        default return ""
    default return $type
};

declare function local:function-xquery-signatures($function as element(apidoc:function)) as xs:string* {
    let $name := local:function-name($function)
    let $params :=
        for $name in local:function-parameters($function)
        let $type := local:function-parameter-type($function, $name)
        return ``[$`{$name}` as `{$type}`]``
    let $type := local:function-return-type($function)
    let $arity-range := local:function-arity($function)
    for $arity in $arity-range?min to $arity-range?max
    let $params := $params[position() = 1 to $arity]
    return if ($type = "") then
        ``[declare function `{$name}`(`{string-join($params, ", ")}`) external;]``
    else
        ``[declare function `{$name}`(`{string-join($params, ", ")}`) as `{$type}` external;]``
};

declare function local:function-html-signatures($function as element(apidoc:function)) as element(div)+ {
    let $name := local:function-name($function)
    let $params :=
        for $name in local:function-parameters($function)
        let $type := local:function-parameter-type($function, $name)
        return

            ${$name},
             as ,
            {$type}

    let $type := local:function-return-type($function)
    let $arity-range := local:function-arity($function)
    for $arity in $arity-range?min to $arity-range?max
    let $params := $params[position() = 1 to $arity]
    return if (count($params) <= 2) then

            {$name}({
                for $param at $i in $params
                return (
                    if ($i > 1) then ", " else (),
                    $param/*
                )
            }){
                if ($type != "") then (
                     as ,
                    xs:double
                ) else ()
            }

    else

{
                (: JEditorPanel does not support vertical-align on tr/td elements, so use valign instead. :)

                    {$name}(
                    {$params[1]/code[@class="arg"]}
                    {$params[1]/code[not(@class="arg")]},

,
                for $param at $i in $params[position() > 1]
                return

                        {$param/code[@class="arg"]}
                        {
                            $param/code[not(@class="arg")],
                            if ($i = count($params) - 1) then ")" else ","
                        }

            }

};

declare function local:function-html-parameters($function as element(apidoc:function)) as element(table)? {
    let $params := local:function-parameters($function)
    return if (exists($params)) then

{
            for $name in local:function-parameters($function)
            let $type := local:function-parameter-type($function, $name)
            let $summary := local:function-parameter($function, $name)
            return

                    ${$name}
                    {
                        for $child in $summary/node()
                        return local:documentation-html($child)
                    }

        }

    else ()
};

(: query ------------------------------------------------------------------- :)

let $prefix := local:prefix($namespaces, $namespace)
for $function in $functions
where $function/@lib = $prefix and $function/@name = $local-name
return (
    local:function-uri($function),
    fn:serialize(local:documentation-html($function/apidoc:summary)),
    string-join(local:function-html-signatures($function) ! fn:serialize(.), ""),
    fn:serialize(local:function-html-parameters($function)),
    fn:serialize($function/apidoc:privilege ! local:documentation-html(.)),
    fn:serialize($function/apidoc:usage ! local:documentation-html(.)),
    fn:serialize($function/apidoc:example ! local:documentation-html(.)),
    ()
)

(:
 : Copyright (C) 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 "3.1";

declare namespace apidoc = "http://marklogic.com/xdmp/apidoc";
declare namespace map = "http://www.w3.org/2005/xpath-functions/map";
declare namespace xhtml = "http://www.w3.org/1999/xhtml";

declare variable $marklogic-version as xs:string external;

declare variable $language as xs:string external := "xquery"; (: xquery | javascript | rest :)
declare variable $namespace as xs:string external;
declare variable $local-name as xs:string external;

declare variable $apidoc as element(apidoc:apidoc) :=
    typeswitch (.)
    case xs:string return fn:parse-xml(.)/element()
    case document-node() return ./element()
    default return .;

(: documentation helpers --------------------------------------------------- :)

declare function local:apidoc-language($doc as element()) as xs:string {
    ($doc/@class, "xquery")[1]
};

declare function local:prefix($namespaces as map(*), $namespace as xs:string) as xs:string {
    for $prefix in map:keys($namespaces)
    where map:get($namespaces, $prefix) = $namespace
    return $prefix
};

declare function local:documentation-html($doc as node()) as node()* {
    if ($doc/namespace-uri() = "http://marklogic.com/xdmp/apidoc") then
        let $first :=
            let $node := $doc/node()[position() = 1]
            return if ($node instance of text() and string-length($node/normalize-space()) != 0) then
                ()
            else
                $node
        return if (exists($first) and (some $child in $doc/node() satisfies $child instance of element())) then
            if (local:apidoc-language($doc) = $language) then
                for $child in $doc/node()
                return local:documentation-html($child)
            else ()
        else

{$doc/node()}

    else if ($doc instance of text()) then
        let $text := $doc/normalize-space()
        return if ($text != "") then
            $doc
        else ()
    else if ($doc instance of element() and local:apidoc-language($doc) = $language) then
        element { $doc/local-name() } {
            for $child in $doc/node()
            return local:documentation-html($child)
        }
    else ()
};

(: namespaces -------------------------------------------------------------- :)

declare variable $module-namespaces := map:merge(
    for $import in $apidoc//apidoc:module/apidoc:summary//(*:p|*:pre)
    let $match := fn:analyze-string(($import/*:code, $import)[1], "import module (namespace\s*([a-z0-9]+)\s*=\s*)?""([^""]+)""")/fn:match[1]
    let $prefix := $import/ancestor::apidoc:module/@lib
    let $namespace := $match/fn:group[@nr = "3"]/string()
    where exists($namespace)
    return map:entry($prefix, $namespace)
);

declare variable $xquery-namespaces := map {
    "local": "http://www.w3.org/2005/xquery-local-functions",
    "fn": "http://www.w3.org/2005/xpath-functions",
    "xml": "http://www.w3.org/XML/1998/namespace",
    "xs": "http://www.w3.org/2001/XMLSchema",
    "xsi": "http://www.w3.org/2001/XMLSchema-instance"
};

declare variable $marklogic-5-builtin := map {
    "cts": "http://marklogic.com/cts",
    "dbg": "http://marklogic.com/xdmp/dbg",
    "dir": "http://marklogic.com/xdmp/directory",
    "error": "http://marklogic.com/xdmp/error",
    "map": "http://marklogic.com/xdmp/map",
    "math": "http://marklogic.com/xdmp/math",
    "prof": "http://marklogic.com/xdmp/profile",
    "sec": "http://marklogic.com/security",
    "spell": "http://marklogic.com/xdmp/spell",
    "xdmp": "http://marklogic.com/xdmp"
};

declare variable $marklogic-6-builtin := map {
    "err": "http://www.w3.org/2005/xqt-error"
};

declare variable $marklogic-7-builtin := map {
    "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
    "sc": "http://marklogic.com/xdmp/schema-components",
    "sql": "http://marklogic.com/xdmp/sql"
};

declare variable $marklogic-10-builtin := map {
    "cntk": "http://marklogic.com/cntk",
    "ort": "http://marklogic.com/onnxruntime"
};

declare variable $marklogic-additional := map {
    "as": "http://marklogic.com/xdmp/assignments",
    "db": "http://marklogic.com/xdmp/database",
    "dg": "xdmp:document-get",
    "cl": "http://marklogic.com/xdmp/clusters",
    "exsl": "http://exslt.org/common",
    "extusr": "http://marklogic.com/xdmp/external/user",
    "gr": "http://marklogic.com/xdmp/group",
    "lang": "http://marklogic.com/xdmp/language",
    "list": "http://marklogic.com/manage/package/list",
    "md": "urn:oasis:names:tc:SAML:2.0:metadata",
    "mt": "http://marklogic.com/xdmp/mimetypes",
    "pkg": "http://marklogic.com/manage/package",
    "s": "http://www.w3.org/2009/xpath-functions/analyze-string",
    "sch": "http://purl.oclc.org/dsdl/schematron",
    "x509": "http://marklogic.com/xdmp/x509",
    "xdt": "http://www.w3.org/2004/10/xpath-datatypes",
    "xi": "http://www.w3.org/2001/XInclude"
};

declare variable $namespaces := map:merge((
    $module-namespaces,
    $xquery-namespaces,
    $marklogic-5-builtin,
    $marklogic-6-builtin,
    $marklogic-7-builtin,
    $marklogic-10-builtin,
    $marklogic-additional,
    ()
));

(: functions --------------------------------------------------------------- :)

(: Several functions in the apidocs have duplicate parameter names in some versions, so fix these. :)
declare variable $param-fixes := map {
    "fn:subtract-dateTimes-yielding-dayTimeDuration": ("srcval1", "srcval2"),
    "fn:subtract-dateTimes-yielding-yearMonthDuration": ("srcval1", "srcval2"),
    "geo:region-contains": ("target", "region", "options"),
    "math:fmod": ("x", "y"),
    "math:rank": ("arg1", "arg2", "options")
};

declare variable $functions as element(apidoc:function)* := $apidoc//apidoc:function[
    local:function-language(.) = $language and not(@name = "")
];

declare function local:function-uri($function as element(apidoc:function)) as xs:string {
    ``[http://docs.marklogic.com/`{$marklogic-version}`/`{local:function-name($function)}`]``
};

declare function local:function-language($function as element(apidoc:function)) as xs:string {
    let $bucket := $function/@bucket
    return switch ($bucket)
    case "REST Resources API" return "rest"
    default return local:apidoc-language($function)
};

declare function local:function-name($function as element(apidoc:function)) as xs:string {
    ``[`{$function/@lib}`:`{$function/@name}`]``
};

declare function local:function-parameters($function as element(apidoc:function)) as xs:string* {
    let $names as xs:string* :=
        let $names := map:get($param-fixes, local:function-name($function))
        return if (exists($names)) then
            $names
        else
            $function/apidoc:params/apidoc:param[local:apidoc-language(.) = $language]/@name/string()
    return if (count($names) != count(distinct-values($names))) then
        fn:error(xs:QName("err:XQST0039"),``[Duplicate parameter name in `{local:function-name($function)}`]``)
    else
        $names
};

declare function local:function-arity($function as element(apidoc:function)) as map(*) {
    let $params := $function/apidoc:params/apidoc:param[local:apidoc-language(.) = $language]
    return map {
        "min": count($params[not(@optional = "true")]),
        "max": count($params)
    }
};

declare function local:function-parameter($function as element(apidoc:function), $name as xs:string) as element(apidoc:param) {
    let $names := map:get($param-fixes, local:function-name($function))
    return if (exists($names)) then
        let $i := fn:index-of($names, $name)
        return $function/apidoc:params/apidoc:param[$i]
    else
        $function/apidoc:params/apidoc:param[@name = $name and local:apidoc-language(.) = $language]
};

declare function local:function-parameter-type($function as element(apidoc:function), $name as xs:string) as xs:string {
    let $type := local:function-parameter($function, $name)/@type/string()
    return switch ($type)
    case "atomic type" return "item()*"
    case "xs:string)" return "xs:string"
    case "xs:dateTime? | xs:date? | xs:string?" return "(xs:dateTime?|xs:date?|xs:string?)"
    case "binary())" return "binary()"
    case "element(sec:query-rolesets)*)" return "element(sec:query-rolesets)*"
    case "function()" return "function(*)"
    case "item()* | map:map" return "(item()*|map:map)"
    case "(binary()|node())*" return "(binary()*|node()*)"
    case "(binary()|node())?" return "(binary()?|node()?)"
    case "(element()|map:map)?" case "element()?|map:map?" return "(element()?|map:map?)"
    case "(node()? | map:map)?" return "(node()?|map:map?)"
    case "(cts:order|xs:string)*" return "(cts:order*|xs:string*)"
    case "[xs:string?]" return "xs:string?"
    default return replace($type, ",\.\.\.", "...")
};

declare function local:function-return-type($function as element(apidoc:function)) as xs:string {
    let $type := normalize-space($function/apidoc:return[local:apidoc-language(.) = $language])
    return switch ($type)
    case "An XML representation of the certificate." return "element()?"
    case "element())" case "Element()" return "element()"
    case "element()|map:map" return "(element()|map:map)"
    case "element(xsd:schema)*" return "element(xs:schema)*"
    case "empty-sequence" case "empty sequence" return "empty-sequence()"
    case "xs:string)" return "xs:string"
    case "xs:unsignedLong)" return "xs:unsignedLong"
    case "pkgins:install($pkgname)" return "element(pkg:install-status)"
    case "pkgins:revert($ticket)" return "element(pkg:revert-status)"
    case "query-results-serialize($results)" return "item()*"
    case "The return data type is the data type of the date argument" return "item()"
    case "" return
        switch (local:function-name($function))
        case "admin:appserver-set-output-indent-tabs" return "element(configuration)"
        default return ""
    default return $type
};

declare function local:function-xquery-signatures($function as element(apidoc:function)) as xs:string* {
    let $name := local:function-name($function)
    let $params :=
        for $name in local:function-parameters($function)
        let $type := local:function-parameter-type($function, $name)
        return ``[$`{$name}` as `{$type}`]``
    let $type := local:function-return-type($function)
    let $arity-range := local:function-arity($function)
    for $arity in $arity-range?min to $arity-range?max
    let $params := $params[position() = 1 to $arity]
    return if ($type = "") then
        ``[declare function `{$name}`(`{string-join($params, ", ")}`) external;]``
    else
        ``[declare function `{$name}`(`{string-join($params, ", ")}`) as `{$type}` external;]``
};

declare function local:function-html-signatures($function as element(apidoc:function)) as element(div)+ {
    let $name := local:function-name($function)
    let $params :=
        for $name in local:function-parameters($function)
        let $type := local:function-parameter-type($function, $name)
        return

            ${$name},
             as ,
            {$type}

    let $type := local:function-return-type($function)
    let $arity-range := local:function-arity($function)
    for $arity in $arity-range?min to $arity-range?max
    let $params := $params[position() = 1 to $arity]
    return if (count($params) <= 2) then

            {$name}({
                for $param at $i in $params
                return (
                    if ($i > 1) then ", " else (),
                    $param/*
                )
            }){
                if ($type != "") then (
                     as ,
                    xs:double
                ) else ()
            }

    else

{
                (: JEditorPanel does not support vertical-align on tr/td elements, so use valign instead. :)

                    {$name}(
                    {$params[1]/code[@class="arg"]}
                    {$params[1]/code[not(@class="arg")]},

,
                for $param at $i in $params[position() > 1]
                return

                        {$param/code[@class="arg"]}
                        {
                            $param/code[not(@class="arg")],
                            if ($i = count($params) - 1) then ")" else ","
                        }

            }

};

declare function local:function-html-parameters($function as element(apidoc:function)) as element(table)? {
    let $params := local:function-parameters($function)
    return if (exists($params)) then

{
            for $name in local:function-parameters($function)
            let $type := local:function-parameter-type($function, $name)
            let $summary := local:function-parameter($function, $name)
            return

                    ${$name}
                    {$summary/node()}

        }

    else ()
};

(: query ------------------------------------------------------------------- :)

let $prefix := local:prefix($namespaces, $namespace)
for $function in $functions
where $function/@lib = $prefix and $function/@name = $local-name
return (
    local:function-uri($function),
    fn:serialize(local:documentation-html($function/apidoc:summary)),
    string-join(local:function-html-signatures($function) ! fn:serialize(.), ""),
    fn:serialize(local:function-html-parameters($function)),
    fn:serialize($function/apidoc:privilege ! local:documentation-html(.)),
    fn:serialize($function/apidoc:usage ! local:documentation-html(.)),
    fn:serialize($function/apidoc:example ! local:documentation-html(.)),
    ()
)


Fixed an error if multiple specifications were references.

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

xquery version "1.0";

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

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

declare variable $xqts:XML_HIGHLIGHT_STYLE { "/db/XQTS/xml-highlight.xsl" };
declare variable $xqts:CONFIG { xqts:initialize() };
declare variable $xqts:XQTS_HOME { $xqts:CONFIG/basedir/text() };

declare function xqts:initialize() as element() {
    let $collection := xdb:create-collection("/db", "XQTS")
    let $config := doc("/db/XQTS")/config
    return
        if ($config) then
            $config
        else
            let $home := util:system-property("exist.home")
            let $path := concat($home, "/tools/XQTS")
            let $stored := xdb:store-files-from-pattern("/db/XQTS", $path, "*.xml", "text/xml")
            return
                doc("/db/XQTS/config.xml")/config
};

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

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

declare function xqts:path-to-uri($path as xs:string) as xs:string {
        if (starts-with($path, "/")) then
            concat("file://", $path)
        else
            concat("file:///", $path)
};

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

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

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

xquery version "1.0";

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

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

declare variable $xqts:XML_HIGHLIGHT_STYLE { "/db/XQTS/xml-highlight.xsl" };
declare variable $xqts:CONFIG { xqts:initialize() };
declare variable $xqts:XQTS_HOME { $xqts:CONFIG/basedir/text() };

declare function xqts:initialize() as element() {
    let $collection := xdb:create-collection("/db", "XQTS")
    let $config := doc("/db/XQTS")/config
    return
        if ($config) then
            $config
        else
            let $home := util:system-property("exist.home")
            let $path := concat($home, "/tools/XQTS")
            let $stored := xdb:store-files-from-pattern("/db/XQTS", $path, "*.xml", "text/xml")
            return
                doc("/db/XQTS/config.xml")/config
};

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

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

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)
   let $tokenized := tokenize($xq-string, "\n")
   for $token in $tokenized return
       ($token,
)
};

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

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


Add test for #1108 - map wildcard lookup

xquery version "1.0";

module namespace mt="http://exist-db.org/xquery/test/maps";

import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare variable $mt:daysOfWeek :=
    map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday",
        "Sa" : "Saturday"
    };

declare %test:assertEquals("Wednesday") function mt:createLiteral1() {
    $mt:daysOfWeek("We")
};

declare %test:assertEquals("Wednesday") function mt:createWithIntKeys() {
    let $map := map {
        1 : "Sunday",
        2 : "Monday",
        3 : "Tuesday",
        4 : "Wednesday",
        5 : "Thursday",
        6 : "Friday",
        7 : "Saturday"
    }
    return
        $map(4)
};

declare %test:assertEquals(20) function mt:createWithFunctionValue() {
    let $fn := function($p) { $p * 2 }
    let $map := map { "callback" : $fn }
    return
        map:get($map, "callback")(10)
};

declare %test:assertEquals("Sunday") function mt:createWithEntry() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    return
        $map("Su")
};

declare %test:assertXPath("count($result) = 8") %test:assertXPath("7 = $result")
function mt:createFromTwoMaps() {
    let $week := map{0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag", 5: "Freitag", 6: "Samstag"}
    let $map := map:merge(($week, map { 7 : "Sonntag" }))
    return
        map:keys($map)
};

declare
    %test:assertEquals(0)
function mt:size-empty() {
    let $m := map {}
    return
      map:size($m)
};

declare
    %test:assertEquals("Good")
function mt:put-empty() {
    let $m := map {}
    return
      map:put($m, "Cats", "Good")("Cats")
};

declare
    %test:assertEquals("Bad")
function mt:put-single() {
    let $m := map {
        "Cats" : "Good"
    }
    return
      map:put($m, "Dogs", "Bad")("Dogs")
};

declare
    %test:assertEquals("Duck")
function mt:put() {
    let $m := map {
        "Cats" : "Good",
        "Dogs" : "Bad",
        1 : "Chicken"
    }
    return
      map:put($m, 2, "Duck")(2)
};

declare
    %test:assertEquals(4)
function mt:size() {
    let $m := map {
      "Cats" : "Good",
      "Dogs" : "Bad",
      1 : "Chicken",
      2 : "Duck"
    }
    return
      map:size($m)
};

declare
    %test:assertEquals("Sonntag", "Dienstag", "Donnerstag", "Samstag")
function mt:for-each() {
    let $week := map{0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag", 5: "Freitag", 6: "Samstag"}
    return
        map:for-each($week, function($key, $value) {
            if ($key mod 2 = 0) then
                $value
            else
                ()
        })
};

declare
    %test:assertEquals(3)
function mt:for-each2() {
    let $nm := map:merge(map:for-each(map{"a":1, "b":2}, function($k, $v){map:entry($k, $v+1)}))
    return
        $nm?b
};

declare %test:assertEquals("Sunday") function mt:createWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        $map("Su")
};

declare %test:assertEquals("Samstag", "Sonnabend") function mt:overwriteKeyInNewMap() {
    let $week := map {0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag", 5: "Freitag", 6: "Samstag"}
    let $map := map:merge(($week, map { 6 :  "Sonnabend" }))
    return
        ($week(6), $map(6))
};

declare %test:assertEmpty function mt:mapEmptyValue() {
    let $map := map {0: (), 1 : ("One", "Two") }
    return
        $map(0)
};

declare %test:assertEquals("One", "Two") function mt:mapSequenceValue() {
    let $map := map {0: (), 1 : ("One", "Two") }
    return
        $map(1)
};

declare %test:assertEquals("Heinz", "Roland", "Uschi", "Verona") function mt:keyTypeDate () {
    let $map := map {
        xs:date("1975-03-19") : "Uschi",
        xs:date("1980-01-22") : "Verona",
        xs:date("1960-06-14") : "Heinz",
        xs:date("1963-10-21") : "Roland"
    }
    for $key in map:keys($map)
    let $name := $map($key)
    order by $name ascending
    return
        $name
};

declare %test:assertEquals(0, "One") function mt:mixedKeyTypes() {
    let $map := map{ "Zero" : 0, 1 : "One" }
    return
        ($map("Zero"), $map(1))
};

declare %test:assertTrue function mt:containsOnEmptyValue() {
    let $map := map{0: () }
    return
        map:contains($map, 0)
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th", "Tu", "We") function mt:keys() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    for $day in map:keys($map)
    order by $day ascending
    return
        $day
};

declare %test:assertEquals("Su") function mt:keysOnMapWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:keys($map)
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th") function mt:remove() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    for $day in map:keys(map:remove(map:remove($map, "We"), "Tu"))
    order by $day
    return
        $day
};

declare %test:assertFalse function mt:remove() {
    let $days := ("Monday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    return
        map:contains(map:remove($map, "Tu"), "Tu")
};

declare %test:assertEmpty function mt:removeSingleKey() {
    let $map := map:entry("Su", "Sunday")
    let $empty := map:remove($map, "Su")
    return
        map:keys($empty)
};

declare %test:assertTrue function mt:contains() {
    map:contains($mt:daysOfWeek, "We")
};

declare %test:assertFalse function mt:containsOnMissingKey() {
    map:contains($mt:daysOfWeek, "Al")
};

declare %test:assertTrue function mt:containsSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:contains($map, "Su")
};

declare %test:assertEquals("Hello world") function mt:computedKeyValue() {
    let $map := map { 2 + 1 : concat("Hello ", "world") }
    return
        $map(3)
};

declare %test:assertEquals("false", "true") function mt:immutability() {
    let $map := map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday"
    }
    let $map2 := map:merge(($map, map:entry("Sa", "Saturday")))
    return
        (map:contains($map, "Sa"), map:contains($map2, "Sa"))
};

declare %test:assertTrue function mt:immutability2() {
    let $map := map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday"
    }
    let $map2 := map:remove($map, "Fr")
    return
        map:contains($map, "Fr")
};

declare %test:assertFalse function mt:immutability3() {
    let $map := map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday"
    }
    let $map2 := map:remove($map, "Fr")
    return
        map:contains($map2, "Fr")
};

declare %test:assertTrue function mt:immutability4() {

    let $daysOfWeek :=  map {   "Sunday" : 1,
                                 "Monday" : 2,
                                 "Tuesday" : 3,
                                 "Wednesday" : 4,
                                 "Thursday" : 5,
                                 "Friday" : 6,
                                 "Saturday" : 7
                             }
    let $workDays := map:remove($daysOfWeek, "Sunday")

    return map:contains($workDays,"Monday")
};

declare %test:assertEquals("Sunday") function mt:sequenceType1() {
    let $map := map { 1 : "Sunday" }
    return
        map:get(mt:mapTest($map), 1)
};

declare %private function mt:mapTest($map as map(*)) as map(xs:integer, xs:string) {
    $map
};

declare
    %test:assertError("EXMPDY001")
    %test:name("Throw error if key is not a single atomic value")
function mt:wrongCardinality() {
    let $map := map { (1, 2) : "illegal" }
    return
        $map(1)
};

declare
    %test:assertEquals("two")
function mt:nestedMaps() {
    let $map := map { 1: map { 1: "one", 2: "two" } }
    return
        $map(1)(2)
};

declare
    %test:assertEquals("Monday")
function mt:nestedMaps2() {
    let $map := map { "week" := map { "days" : $mt:daysOfWeek } }
    return
        $map("week")("days")("Mo")
};

declare
    %test:assertEquals(2)
function mt:qnameKeys() {
    let $map := map { xs:QName("mt:one") : 1, xs:QName("mt:two") : 2 }
    return
        $map(xs:QName("mt:two"))
};

declare
    %test:assertEquals(2)
function mt:longKeys() {
    let $map := map { xs:long(1) : 1, xs:long(2) : 2 }
    return
        $map(2)
};

declare
    %test:args(2)
    %test:assertEquals(3)
    %test:args("Three")
    %test:assertEmpty
function mt:doubleKeys($key as item()) {
    let $map := map { xs:double(1.1) : 1, xs:double(2) : 2 }
    return
        map:merge(($map, map:entry(xs:double(2), 3)))($key)
};

declare
    %test:assertEquals(2, "value")
function mt:mixedNumeric() {
    let $map := map { 1.1 : 1, 2 : 2, "key" : "value" }
    return
        ($map(2), $map("key"))
};

declare
    %test:assertEquals("<c ns='c'/>", "<c ns='c'/>")
function mt:pathExpr() as element(c)+ {
    let $test :=
        <a>
            <b ns="b">
                <c ns="c"/>
            </b>
        </a>
    let $map :=
        map {
            "a" : $test//c,
            "b" : ($test//c)
        }
    return
        ($map("a"), $map("b"))
};

declare
    %test:assertEquals("What were you thinking?")
function mt:lookupUnaryOperator() {
    let $errors := (
      map { "level" : 1, "text" : "Boys will be boys ..." },
      map { "level" : 2, "text" : "What were you thinking?" },
      map { "level" : 3, "text" : "Call the cops!" }
    )
    return $errors[?level = 2]?text
};

declare
    %test:assertEquals("W0342", "M0535")
function mt:lookupMultipleMaps() {
    let $maps := ( map { "id" : "W0342" }, map { "id" : "M0535" } )
    return $maps?id
};

declare
    %test:assertEquals("W0342", "M0535")
function mt:lookupMultipleMaps2() {
    ( map { "id" : "W0342" }, map { "id" : "M0535" } )?id
};

declare
    %test:assertEquals("large")
function mt:lookupNestedMap() {
    let $map := map {
        "name": "sofa", "keys": map { "price": 200.0, "size": "large" }
    }
    return
        $map?keys?size
};

declare
    %test:args("One")
    %test:assertEquals(1)
    %test:args("Two")
    %test:assertEquals("2")
function mt:lookupParenthesized($key as xs:string) {
    let $map := map { "one": 1, "two": "2" }
    return
        $map?(lower-case($key))
};

declare
    %test:assertError
function mt:lookupWrongType() {
    let $map := map { "one": 1, "two": "2" }
    let $str := "Hello"
    return
        ($map, $str)?one
};

declare
    %test:assertTrue
function mt:lookupWildcard() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := $mt:daysOfWeek
    return
        every $day in $map?* satisfies $day = $days
};

declare
    %test:assertEquals(1)
function mt:compat() {
    let $map := map { "one":= 1, "two":= "2" }
    return
        $map("one")
};

declare
    %test:assertError
function mt:no-atomization() {
    data(map { "k": "v" })
};

xquery version "1.0";

module namespace mt="http://exist-db.org/xquery/test/maps";

import module namespace test="http://exist-db.org/xquery/xqsuite" at "resource:org/exist/xquery/lib/xqsuite/xqsuite.xql";

declare variable $mt:daysOfWeek :=
    map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday",
        "Sa" : "Saturday"
    };

declare %test:assertEquals("Wednesday") function mt:createLiteral1() {
    $mt:daysOfWeek("We")
};

declare %test:assertEquals("Wednesday") function mt:createWithIntKeys() {
    let $map := map {
        1 : "Sunday",
        2 : "Monday",
        3 : "Tuesday",
        4 : "Wednesday",
        5 : "Thursday",
        6 : "Friday",
        7 : "Saturday"
    }
    return
        $map(4)
};

declare %test:assertEquals(20) function mt:createWithFunctionValue() {
    let $fn := function($p) { $p * 2 }
    let $map := map { "callback" : $fn }
    return
        map:get($map, "callback")(10)
};

declare %test:assertEquals("Sunday") function mt:createWithEntry() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    return
        $map("Su")
};

declare %test:assertXPath("count($result) = 8") %test:assertXPath("7 = $result")
function mt:createFromTwoMaps() {
    let $week := map{0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag", 5: "Freitag", 6: "Samstag"}
    let $map := map:merge(($week, map { 7 : "Sonntag" }))
    return
        map:keys($map)
};

declare
    %test:assertEquals(0)
function mt:size-empty() {
    let $m := map {}
    return
      map:size($m)
};

declare
    %test:assertEquals("Good")
function mt:put-empty() {
    let $m := map {}
    return
      map:put($m, "Cats", "Good")("Cats")
};

declare
    %test:assertEquals("Bad")
function mt:put-single() {
    let $m := map {
        "Cats" : "Good"
    }
    return
      map:put($m, "Dogs", "Bad")("Dogs")
};

declare
    %test:assertEquals("Duck")
function mt:put() {
    let $m := map {
        "Cats" : "Good",
        "Dogs" : "Bad",
        1 : "Chicken"
    }
    return
      map:put($m, 2, "Duck")(2)
};

declare
    %test:assertEquals(4)
function mt:size() {
    let $m := map {
      "Cats" : "Good",
      "Dogs" : "Bad",
      1 : "Chicken",
      2 : "Duck"
    }
    return
      map:size($m)
};

declare
    %test:assertEquals("Sonntag", "Dienstag", "Donnerstag", "Samstag")
function mt:for-each() {
    let $week := map{0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag", 5: "Freitag", 6: "Samstag"}
    return
        map:for-each($week, function($key, $value) {
            if ($key mod 2 = 0) then
                $value
            else
                ()
        })
};

declare
    %test:assertEquals(3)
function mt:for-each2() {
    let $nm := map:merge(map:for-each(map{"a":1, "b":2}, function($k, $v){map:entry($k, $v+1)}))
    return
        $nm?b
};

declare %test:assertEquals("Sunday") function mt:createWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        $map("Su")
};

declare %test:assertEquals("Samstag", "Sonnabend") function mt:overwriteKeyInNewMap() {
    let $week := map {0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag", 5: "Freitag", 6: "Samstag"}
    let $map := map:merge(($week, map { 6 :  "Sonnabend" }))
    return
        ($week(6), $map(6))
};

declare %test:assertEmpty function mt:mapEmptyValue() {
    let $map := map {0: (), 1 : ("One", "Two") }
    return
        $map(0)
};

declare %test:assertEquals("One", "Two") function mt:mapSequenceValue() {
    let $map := map {0: (), 1 : ("One", "Two") }
    return
        $map(1)
};

declare %test:assertEquals("Heinz", "Roland", "Uschi", "Verona") function mt:keyTypeDate () {
    let $map := map {
        xs:date("1975-03-19") : "Uschi",
        xs:date("1980-01-22") : "Verona",
        xs:date("1960-06-14") : "Heinz",
        xs:date("1963-10-21") : "Roland"
    }
    for $key in map:keys($map)
    let $name := $map($key)
    order by $name ascending
    return
        $name
};

declare %test:assertEquals(0, "One") function mt:mixedKeyTypes() {
    let $map := map{ "Zero" : 0, 1 : "One" }
    return
        ($map("Zero"), $map(1))
};

declare %test:assertTrue function mt:containsOnEmptyValue() {
    let $map := map{0: () }
    return
        map:contains($map, 0)
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th", "Tu", "We") function mt:keys() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    for $day in map:keys($map)
    order by $day ascending
    return
        $day
};

declare %test:assertEquals("Su") function mt:keysOnMapWithSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:keys($map)
};

declare %test:assertEquals("Fr", "Mo", "Sa", "Su", "Th") function mt:remove() {
    let $days := ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    for $day in map:keys(map:remove(map:remove($map, "We"), "Tu"))
    order by $day
    return
        $day
};

declare %test:assertFalse function mt:remove() {
    let $days := ("Monday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
    let $map := map:merge((map(function($day) { map:entry(substring($day, 1, 2), $day) }, $days)))
    return
        map:contains(map:remove($map, "Tu"), "Tu")
};

declare %test:assertEmpty function mt:removeSingleKey() {
    let $map := map:entry("Su", "Sunday")
    let $empty := map:remove($map, "Su")
    return
        map:keys($empty)
};

declare %test:assertTrue function mt:contains() {
    map:contains($mt:daysOfWeek, "We")
};

declare %test:assertFalse function mt:containsOnMissingKey() {
    map:contains($mt:daysOfWeek, "Al")
};

declare %test:assertTrue function mt:containsSingleKey() {
    let $map := map:entry("Su", "Sunday")
    return
        map:contains($map, "Su")
};

declare %test:assertEquals("Hello world") function mt:computedKeyValue() {
    let $map := map { 2 + 1 : concat("Hello ", "world") }
    return
        $map(3)
};

declare %test:assertEquals("false", "true") function mt:immutability() {
    let $map := map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday"
    }
    let $map2 := map:merge(($map, map:entry("Sa", "Saturday")))
    return
        (map:contains($map, "Sa"), map:contains($map2, "Sa"))
};

declare %test:assertTrue function mt:immutability2() {
    let $map := map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday"
    }
    let $map2 := map:remove($map, "Fr")
    return
        map:contains($map, "Fr")
};

declare %test:assertFalse function mt:immutability3() {
    let $map := map {
        "Su" : "Sunday",
        "Mo" : "Monday",
        "Tu" : "Tuesday",
        "We" : "Wednesday",
        "Th" : "Thursday",
        "Fr" : "Friday"
    }
    let $map2 := map:remove($map, "Fr")
    return
        map:contains($map2, "Fr")
};

declare %test:assertTrue function mt:immutability4() {

    let $daysOfWeek :=  map {   "Sunday" : 1,
                                 "Monday" : 2,
                                 "Tuesday" : 3,
                                 "Wednesday" : 4,
                                 "Thursday" : 5,
                                 "Friday" : 6,
                                 "Saturday" : 7
                             }
    let $workDays := map:remove($daysOfWeek, "Sunday")

    return map:contains($workDays,"Monday")
};

declare %test:assertEquals("Sunday") function mt:sequenceType1() {
    let $map := map { 1 : "Sunday" }
    return
        map:get(mt:mapTest($map), 1)
};

declare %private function mt:mapTest($map as map(*)) as map(xs:integer, xs:string) {
    $map
};

declare
    %test:assertError("EXMPDY001")
    %test:name("Throw error if key is not a single atomic value")
function mt:wrongCardinality() {
    let $map := map { (1, 2) : "illegal" }
    return
        $map(1)
};

declare
    %test:assertEquals("two")
function mt:nestedMaps() {
    let $map := map { 1: map { 1: "one", 2: "two" } }
    return
        $map(1)(2)
};

declare
    %test:assertEquals("Monday")
function mt:nestedMaps2() {
    let $map := map { "week" := map { "days" : $mt:daysOfWeek } }
    return
        $map("week")("days")("Mo")
};

declare
    %test:assertEquals(2)
function mt:qnameKeys() {
    let $map := map { xs:QName("mt:one") : 1, xs:QName("mt:two") : 2 }
    return
        $map(xs:QName("mt:two"))
};

declare
    %test:assertEquals(2)
function mt:longKeys() {
    let $map := map { xs:long(1) : 1, xs:long(2) : 2 }
    return
        $map(2)
};

declare
    %test:args(2)
    %test:assertEquals(3)
    %test:args("Three")
    %test:assertEmpty
function mt:doubleKeys($key as item()) {
    let $map := map { xs:double(1.1) : 1, xs:double(2) : 2 }
    return
        map:merge(($map, map:entry(xs:double(2), 3)))($key)
};

declare
    %test:assertEquals(2, "value")
function mt:mixedNumeric() {
    let $map := map { 1.1 : 1, 2 : 2, "key" : "value" }
    return
        ($map(2), $map("key"))
};

declare
    %test:assertEquals("<c ns='c'/>", "<c ns='c'/>")
function mt:pathExpr() as element(c)+ {
    let $test :=
        <a>
            <b ns="b">
                <c ns="c"/>
            </b>
        </a>
    let $map :=
        map {
            "a" : $test//c,
            "b" : ($test//c)
        }
    return
        ($map("a"), $map("b"))
};

declare
    %test:assertEquals("What were you thinking?")
function mt:lookupUnaryOperator() {
    let $errors := (
      map { "level" : 1, "text" : "Boys will be boys ..." },
      map { "level" : 2, "text" : "What were you thinking?" },
      map { "level" : 3, "text" : "Call the cops!" }
    )
    return $errors[?level = 2]?text
};

declare
    %test:assertEquals("W0342", "M0535")
function mt:lookupMultipleMaps() {
    let $maps := ( map { "id" : "W0342" }, map { "id" : "M0535" } )
    return $maps?id
};

declare
    %test:assertEquals("W0342", "M0535")
function mt:lookupMultipleMaps2() {
    ( map { "id" : "W0342" }, map { "id" : "M0535" } )?id
};

declare
    %test:assertEquals("large")
function mt:lookupNestedMap() {
    let $map := map {
        "name": "sofa", "keys": map { "price": 200.0, "size": "large" }
    }
    return
        $map?keys?size
};

declare
    %test:args("One")
    %test:assertEquals(1)
    %test:args("Two")
    %test:assertEquals("2")
function mt:lookupParenthesized($key as xs:string) {
    let $map := map { "one": 1, "two": "2" }
    return
        $map?(lower-case($key))
};

declare
    %test:assertError
function mt:lookupWrongType() {
    let $map := map { "one": 1, "two": "2" }
    let $str := "Hello"
    return
        ($map, $str)?one
};

declare
    %test:assertEquals(1)
function mt:compat() {
    let $map := map { "one":= 1, "two":= "2" }
    return
        $map("one")
};

declare
    %test:assertError
function mt:no-atomization() {
    data(map { "k": "v" })
};


Correct ".d4st" to "_d4st"

Correct ".d4st" to "_d4st"

(: =====================================================

   DFST BaseX Utilities

   Utilities specific to the DFST use of BaseX for managing
   DITA content.

   Author: W. Eliot Kimber

   Copyright (c) 2015 DITA For Small Teams
   Licensed under Apache License 2

   ===================================================== :)

module namespace bxutil="http://dita-for-small-teams.org/xquery/modules/basex-utils";

(:~
 : getGitRepositoryInfos()
 :
 : Returns a list of zero or more <repo> elements, where each <repo>
 : element provides the repository name, branch count, and list of
 : branches in that repository.
 :
 : This function depends on the DFST BaseX database naming convention
 : of "d4st^{repo}^{branch}
 :
 :
 :)
 declare function bxutil:getGitRepositoryInfos() as element(repo)* {
  (: Organize the databases by repo. BaseX dbs for the same repo will start with the same string :)

  let $repos :=
      for $db in db:list-details() order by string($db)
          let $tokens := tokenize(string($db), '\^')
          return if ($tokens[1] = "d4st")
             then <repo name="{$tokens[2]}" branch="{$tokens[3]}"/>
             else ()

   (: Now select repos with the same repository name :)
   return for $name in distinct-values($repos/@name)
       return <repo name="{$name}" branchCount="{count($repos[@name = $name])}">{
              for $branch in $repos[@name = $name]
                  return <branch name="{$branch/@branch}"/>}</repo>

 };

 (: Constructs the BaseX database name for git repository and branch pair :)
 declare function bxutil:getDbNameForRepoAndBranch($repo, $branch) {
   let $sep := '^'
   return concat('d4st', $sep, $repo, $sep, $branch)
 };

 (: Constructs the BaseX metadata database name for git repository and branch pair
  : For each content database, reflecting a specific repository/branch pair,
  : there is a corresonding metadata database that holds any metadata for that
  : database (i.e., all the link management metadata).
  :)
 declare function bxutil:getMetadataDbNameForRepoAndBranch($repo, $branch) {
   let $sep := '^'
   return concat('_d4st', $sep, 'metadata', $sep, $repo, $sep, $branch)
 };

 (: Gets the metadata database name for given document.
  :
  :)
 declare function bxutil:getMetadataDbNameForDoc($doc as document-node()) {
   let $sep := '^'
   let $repo := bxutil:getGitRepoForDoc($doc)
   let $branch := bxutil:getGitBranchForDoc($doc)
   return bxutil:getMetadataDbNameForRepoAndBranch($repo, $branch)
 };

 (: Gets the git repository for a document  :)
 declare function bxutil:getGitRepoForDoc($doc as document-node()) {
    let $uri := document-uri($doc)
    return if (starts-with($uri, 'd4st^'))
       then
         let $db := tokenize($uri, '/')[1]
         let $gitMetadata := bxutil:getGitMetadata($db)
         return string($gitMetadata/gitstate/repo)
       else 'No associated git repository'
 };

 (: Gets the git repository for a document  :)
 declare function bxutil:getGitBranchForDoc($doc as document-node()) {
    let $uri := document-uri($doc)
    return if (starts-with($uri, 'd4st^'))
       then
         let $db := tokenize($uri, '/')[1]
         let $gitMetadata := bxutil:getGitMetadata($db)
         return string($gitMetadata/gitstate/branch)
       else 'No associated git repository'
 };

 (: Gets the git repository for a document  :)
 declare function bxutil:getGitCommitForDoc($doc as document-node()) {
    let $uri := document-uri($doc)
    return if (starts-with($uri, 'd4st^'))
       then
         let $db := tokenize($uri, '/')[1]
         let $gitMetadata := bxutil:getGitMetadata($db)
         return string($gitMetadata/gitstate/commit)
       else 'No associated git repository'
 };

 (: Gets the git metadata document for the database :)
 declare function bxutil:getGitMetadata($db as xs:string) as element(d4st_metadata)? {
   let $uri as xs:string := concat($db, '/_d4st/metadata.xml')
   return
   try {
     doc($uri)/*
   } catch * {
     ()
   }

 };

 (: Given a document, returns the path to the doc, omitting the database name :)
 declare function bxutil:getPathForDoc($doc as document-node()) as xs:string? {
   bxutil:getPathForDocURI(document-uri($doc))
 };

 declare function bxutil:getPathForDocURI($uri as xs:string) as xs:string? {
   string-join(tokenize($uri, '/')[position() gt 1], '/')
 };

 (:~
  : Report a map as XML for debugging purposes
  :
  : @return a sequence of zero or more elements, one for each
  : element in the map, where the tagname is the key name (assumes
  : string keys) and the contents are the serialized value of the
  : the map element.
  :)
declare function bxutil:reportMapAsXML($map as map(*)) as element()* {
   let $result :=
       for $key in map:keys($map)
           let $member := $map($key)
           return element item {
              attribute key { $key },
              typeswitch ($member)
                case attribute()
                  return <att name="{name($member)}">string($member)</att>
                case map(*)
                  return bxutil:reportMapAsXML($member)
                default
                  return $member
           }
    return $result
};
(: End of Module :)

(: =====================================================

   DFST BaseX Utilities

   Utilities specific to the DFST use of BaseX for managing
   DITA content.

   Author: W. Eliot Kimber

   Copyright (c) 2015 DITA For Small Teams
   Licensed under Apache License 2

   ===================================================== :)

module namespace bxutil="http://dita-for-small-teams.org/xquery/modules/basex-utils";

(:~
 : getGitRepositoryInfos()
 :
 : Returns a list of zero or more <repo> elements, where each <repo>
 : element provides the repository name, branch count, and list of
 : branches in that repository.
 :
 : This function depends on the DFST BaseX database naming convention
 : of "d4st^{repo}^{branch}
 :
 :
 :)
 declare function bxutil:getGitRepositoryInfos() as element(repo)* {
  (: Organize the databases by repo. BaseX dbs for the same repo will start with the same string :)

  let $repos :=
      for $db in db:list-details() order by string($db)
          let $tokens := tokenize(string($db), '\^')
          return if ($tokens[1] = "d4st")
             then <repo name="{$tokens[2]}" branch="{$tokens[3]}"/>
             else ()

   (: Now select repos with the same repository name :)
   return for $name in distinct-values($repos/@name)
       return <repo name="{$name}" branchCount="{count($repos[@name = $name])}">{
              for $branch in $repos[@name = $name]
                  return <branch name="{$branch/@branch}"/>}</repo>

 };

 (: Constructs the BaseX database name for git repository and branch pair :)
 declare function bxutil:getDbNameForRepoAndBranch($repo, $branch) {
   let $sep := '^'
   return concat('d4st', $sep, $repo, $sep, $branch)
 };

 (: Constructs the BaseX metadata database name for git repository and branch pair
  : For each content database, reflecting a specific repository/branch pair,
  : there is a corresonding metadata database that holds any metadata for that
  : database (i.e., all the link management metadata).
  :)
 declare function bxutil:getMetadataDbNameForRepoAndBranch($repo, $branch) {
   let $sep := '^'
   return concat('_d4st', $sep, 'metadata', $sep, $repo, $sep, $branch)
 };

 (: Gets the metadata database name for given document.
  :
  :)
 declare function bxutil:getMetadataDbNameForDoc($doc as document-node()) {
   let $sep := '^'
   let $repo := bxutil:getGitRepoForDoc($doc)
   let $branch := bxutil:getGitBranchForDoc($doc)
   return bxutil:getMetadataDbNameForRepoAndBranch($repo, $branch)
 };

 (: Gets the git repository for a document  :)
 declare function bxutil:getGitRepoForDoc($doc as document-node()) {
    let $uri := document-uri($doc)
    return if (starts-with($uri, 'd4st^'))
       then
         let $db := tokenize($uri, '/')[1]
         let $gitMetadata := bxutil:getGitMetadata($db)
         return string($gitMetadata/gitstate/repo)
       else 'No associated git repository'
 };

 (: Gets the git repository for a document  :)
 declare function bxutil:getGitBranchForDoc($doc as document-node()) {
    let $uri := document-uri($doc)
    return if (starts-with($uri, 'd4st^'))
       then
         let $db := tokenize($uri, '/')[1]
         let $gitMetadata := bxutil:getGitMetadata($db)
         return string($gitMetadata/gitstate/branch)
       else 'No associated git repository'
 };

 (: Gets the git repository for a document  :)
 declare function bxutil:getGitCommitForDoc($doc as document-node()) {
    let $uri := document-uri($doc)
    return if (starts-with($uri, 'd4st^'))
       then
         let $db := tokenize($uri, '/')[1]
         let $gitMetadata := bxutil:getGitMetadata($db)
         return string($gitMetadata/gitstate/commit)
       else 'No associated git repository'
 };

 (: Gets the git metadata document for the database :)
 declare function bxutil:getGitMetadata($db as xs:string) as element(d4st_metadata)? {
   let $uri as xs:string := concat($db, '/.d4st/metadata.xml')
   return
   try {
     doc($uri)/*
   } catch * {
     ()
   }

 };

 (: Given a document, returns the path to the doc, omitting the database name :)
 declare function bxutil:getPathForDoc($doc as document-node()) as xs:string? {
   bxutil:getPathForDocURI(document-uri($doc))
 };

 declare function bxutil:getPathForDocURI($uri as xs:string) as xs:string? {
   string-join(tokenize($uri, '/')[position() gt 1], '/')
 };

 (:~
  : Report a map as XML for debugging purposes
  :
  : @return a sequence of zero or more elements, one for each
  : element in the map, where the tagname is the key name (assumes
  : string keys) and the contents are the serialized value of the
  : the map element.
  :)
declare function bxutil:reportMapAsXML($map as map(*)) as element()* {
   let $result :=
       for $key in map:keys($map)
           let $member := $map($key)
           return element item {
              attribute key { $key },
              typeswitch ($member)
                case attribute()
                  return <att name="{name($member)}">string($member)</att>
                case map(*)
                  return bxutil:reportMapAsXML($member)
                default
                  return $member
           }
    return $result
};
(: End of Module :)


[website] Added tamboti to example package list.

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

xquery version "3.0";

declare namespace ex="http://exist-db.org/xquery/examples";
declare namespace package="http://expath.org/ns/pkg";

declare variable $ex:default-packages :=
    <packages>
        <package uri="http://exist-db.org/apps/demo">
            <abbrev>demo</abbrev>
            <title>eXist-db Demo Apps</title>
            <description>Demonstrates many of eXist's features in one app. Start here
            to get an overview and edit/extend the examples.</description>
        </package>
        <package uri="http://exist-db.org/apps/mobile-function-docs">
            <abbrev>mobile-function-docs</abbrev>
            <title>Mobile Function Documentation</title>
            <description>Shows how to generate HTML for being viewed on a phone.</description>
        </package>
        <package uri="http://exist-db.org/apps/library">
            <abbrev>tamboti</abbrev>
            <title>Tamboti Metadata Framework</title>
            <description>Complex example: a complete search interface and management system
            for bibliographic data.</description>
        </package>
    </packages>
;

declare function local:display-package($name as xs:string, $package as element())
{
    let $pkg := local:metadata($name)
    let $pkg-name := $pkg/package:package/string(@name)
    let $pkg-title := $pkg/package:package/package:title
    let $pkg-abbrev := $pkg/package:package/string(@abbrev)
    let $app-url :=
				if ($pkg//repo:target) then
                	concat(
                    	request:get-context-path(), "/apps",
                    	substring-after($pkg//repo:target, "/db"), "/"
                	)
				else
					()
    return

            Yes
            {$pkg-abbrev}
            {$pkg-title/text()}
            {$package/description/text()}

};

declare function local:metadata($name as xs:string)
{
    <package url="{$name}">
    {
        for $r in ("repo.xml", "expath-pkg.xml")
        let $meta := repo:get-resource($name, $r)
        let $data := if (exists($meta)) then util:binary-to-string($meta) else ()
        return
            if (exists($data)) then
                util:parse($data)
            else
                ()
    }
    {
        let $icon := repo:get-resource($name, "icon.png")
        return
            if (exists($icon)) then
                <icon>icon.png</icon>
            else
                ()
    }
    </package>
};

declare function local:list-packages($packages as element(packages)*)
{

                Installed
                Short Name
                Name
                Description

    {
        let $all := repo:list()
        for $pkg in $packages/package
        return
            if (index-of($all, $pkg/@uri/string())) then
                local:display-package($pkg/@uri/string(), $pkg)
            else

                    No
                    {$pkg/abbrev/text()}
                    {$pkg/title/text()}
                    {$pkg/description/text()}

    }

};

<book xmlns:xi="http://www.w3.org/2001/XInclude">
    <bookinfo>
        <graphic fileref="logo.jpg"/>
        <productname>Open Source Native XML Database</productname>
        <title>eXist-db Demo</title>
        <date>January 2012</date>
        <author>
            <firstname>Wolfgang</firstname>
            <surname>Meier</surname>
        </author>
    </bookinfo>
    <xi:include href="sidebar.xml"/>
    <chapter>
        <title>eXist-db Demo</title>

        <para>We're in the process of moving all examples and demos into separate
        application packages to make it easier for users to view or change them. The
        main set of examples is contained in the <emphasis>DemoApps</emphasis> package.</para>

        <para>The table below shows if the demo apps have been installed into this eXist-db instance.
        If yes, click on the package name to navigate to the main page of the package. If a package
        has not yet been installed, please go to the Package
        Repository page in the admin web app. You can install the demo apps from the
        <emphasis>Public Repo</emphasis>.</para>

        { local:list-packages($ex:default-packages) }

			<title>XForms Examples</title>

			<para>The XForms examples demonstrating the
			integration of betterFORM and XSLTForms have not been moved into installable
			packages yet. Please go to the XForms demo page.
			</para>

    </chapter>
</book>

xquery version "3.0";

declare namespace ex="http://exist-db.org/xquery/examples";
declare namespace package="http://expath.org/ns/pkg";

declare variable $ex:default-packages :=
    <packages>
        <package uri="http://exist-db.org/apps/demo">
            <abbrev>demo</abbrev>
            <title>eXist-db Demo Apps</title>
        </package>
    </packages>
;

declare function local:display-package($name as xs:string)
{
    let $pkg := local:metadata($name)
    let $pkg-name := $pkg/package:package/string(@name)
    let $pkg-title := $pkg/package:package/package:title
    let $pkg-abbrev := $pkg/package:package/string(@abbrev)
    let $app-url :=
				if ($pkg//repo:target) then
                	concat(
                    	request:get-context-path(), "/apps",
                    	substring-after($pkg//repo:target, "/db"), "/"
                	)
				else
					()
    return

            Yes
            {$pkg-abbrev}
            {$pkg-title/text()}

};

declare function local:metadata($name as xs:string)
{
    <package url="{$name}">
    {
        for $r in ("repo.xml", "expath-pkg.xml")
        let $meta := repo:get-resource($name, $r)
        let $data := if (exists($meta)) then util:binary-to-string($meta) else ()
        return
            if (exists($data)) then
                util:parse($data)
            else
                ()
    }
    {
        let $icon := repo:get-resource($name, "icon.png")
        return
            if (exists($icon)) then
                <icon>icon.png</icon>
            else
                ()
    }
    </package>
};

declare function local:list-packages($packages as element(packages)*)
{

                Installed
                Short Name
                Name

    {
        let $all := repo:list()
        for $pkg in $packages/package
        return
            if (index-of($all, $pkg/@uri/string())) then
                local:display-package($pkg/@uri/string())
            else

                    No
                    {$pkg/abbrev/text()}
                    {$pkg/title/text()}

    }

};

<book xmlns:xi="http://www.w3.org/2001/XInclude">
    <bookinfo>
        <graphic fileref="logo.jpg"/>
        <productname>Open Source Native XML Database</productname>
        <title>eXist-db Demo</title>
        <date>January 2012</date>
        <author>
            <firstname>Wolfgang</firstname>
            <surname>Meier</surname>
        </author>
    </bookinfo>
    <xi:include href="sidebar.xml"/>
    <chapter>
        <title>eXist-db Demo</title>

        <para>We're in the process of moving all examples and demos into separate
        application packages to make it easier for users to view or change them. The
        main set of examples is contained in the <emphasis>DemoApps</emphasis> package.</para>

        <para>The table below shows if the demo apps have been installed into this eXist-db instance.
        If yes, click on the package name to navigate to the main page of the package. If a package
        has not yet been installed, please go to the Package
        Repository page in the admin web app. You can install the demo apps from the
        <emphasis>Public Repo</emphasis>.</para>

        { local:list-packages($ex:default-packages) }

			<title>XForms Examples</title>

			<para>The XForms examples demonstrating the
			integration of betterFORM and XSLTForms have not been moved into installable
			packages yet. Please go to the XForms demo page.
			</para>

    </chapter>
</book>