[cleanup] Remove unused jquery.xql

[cleanup] Remove unused jquery.xql

(:
 : eXist-db Open Source Native XML Database
 : Copyright (C) 2001 The eXist-db Authors
 :
 : info@exist-db.org
 : http://www.exist-db.org
 :
 : This library is free software; you can redistribute it and/or
 : modify it under the terms of the GNU Lesser General Public
 : License as published by the Free Software Foundation; either
 : version 2.1 of the License, or (at your option) any later version.
 :
 : This library is distributed in the hope that it will be useful,
 : but WITHOUT ANY WARRANTY; without even the implied warranty of
 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 : Lesser General Public License for more details.
 :
 : You should have received a copy of the GNU Lesser General Public
 : License along with this library; if not, write to the Free Software
 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 :)
(:~
    jQuery module: a set of functions to extend HTML forms with AJAX
    functionality, based on the jQuery javascript library.

    Use: each function takes an XML configuration element as parameter.
    You can either call functions directly from another XQuery module
    or pass a template page to the jquery:process-templates function.
    jquery:process-templates will parse the template page and expand all
    jquery:* elements it knows.

:)
module namespace jquery="http://exist-db.org/xquery/jquery";

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

declare function jquery:script($node as element()?) as xs:string? {
    string-join($node/node(), "")
};

(:~
    Outputs the HTML script and link tags which are required by jQuery.
    You need to call this function once in your HTML head.

<![CDATA[<jquery:header base="scripts/jquery" cssbase="scripts/jquery/css"/>]]>

:)
declare function jquery:header($config as element(jquery:header)) as element()* {
    let $base := $config/@base/string()
    let $cssbase := if ($config/@cssbase) then $config/@cssbase/string() else $base
    let $hasSource := root($config)//jquery:source
    return (
        ,
        ,
        ,
        <link rel="stylesheet" type="text/css" href="{$cssbase}/smoothness/jquery.ui.all.css"/>,
        if ($hasSource) then jquery:syntax-highlighting-libs($base, $cssbase) else ()
    )
};

declare function jquery:syntax-highlighting-libs($base as xs:string, $cssbase as xs:string) {
    ,
    ,
    ,
    ,
    ,
    ,
    <link type="text/css" rel="stylesheet" href="{$base}/../../styles/syntax/shCore.css" />,
    <link type="text/css" rel="Stylesheet" href="{$base}/../../styles/syntax/shThemeDefault.css" id="theme" />,
    <jquery:script>
        SyntaxHighlighter.config.stripBrs = true;
        SyntaxHighlighter.defaults[ 'auto-links'] = false;
        SyntaxHighlighter.defaults[ 'wrap-lines'] = true;
        SyntaxHighlighter.all();
    </jquery:script>
};

(:~
    Generates a jQuery UI tabset from the given configuration element.

    <jquery:tabset>
        <jquery:tab id="simple" label="Simple Search">
            Tab content 1
        </jquery:tab>
        <jquery:tab id="complex" label="Advanced Search">
            Tab content
        </jquery:tab>
    </jquery:tabset>

:)
declare function jquery:tabset($config as element(jquery:tabset)) as element() {
    let $id := if ($config/@id) then $config/@id/string() else util:uuid()
    let $selected := request:get-parameter($id, ())
    let $selectedId :=
        if ($selected) then $config/jquery:tab[@id = $selected]/@id/string() else ()
    return

            {
                for $tab in $config/jquery:tab
                return
                    if ($tab/@href) then

{$tab/@label/string()}

                    else

{$tab/@label/string()}

            }

            {
                for $tab in $config/jquery:tab[@id]
                return

                    {
                        for $child in $tab/node()
                        return
                            jquery:process-templates($child)
                    }

            }
            {
                let $options :=
                    if ($config/@on-select) then
                        concat("var options = { select: ", $config/@on-select, " };")
                    else
                        "var options = null;"
                return
                    <jquery:script>
                        { $options }
                        var tabs = $("#{$id}").tabs(options);
                        {
                            if ($selectedId) then
                                concat("tabs.tabs('select', '", $selectedId, "');")
                            else
                                ()
                        }
                    </jquery:script>
            }

};

(:~
    Creates a repeatable set of form fields. Clicking the trigger will
    clone a given part of the form. The new element is inserted immediately
    after the cloned element.

    The element to be cloned should have a class 'repeat'. It can be an arbitrary
    HTML node. Form fields within the repeated element should have a name attribute
    ending with a number (usually 1), e.g. "input1", "phone1". After inserting a new
    clone, the script will change the names for all form elements in the inserted
    element. So "phone1" will become "phone2" and so on.

    The function expects a configuration element jquery:form-repeat as parameter.
    Two attributes should be specified:

form: a jQuery selector pointing to the HTML form element

trigger: a jQuery selector pointing to the HTML element on which
       the user should click to insert a new row into the form

    Example:

<jquery:form-repeat trigger="#add-field" form="#search-form"/>

    @param $config the jquery:form-repeat configuration element
:)
declare function jquery:form-repeat($config as element(jquery:form-repeat)) as element() {
    let $formSelector := $config/@form/string()
    let $trigger := $config/@trigger/string()
    let $delete := $config/@delete/string()
    let $onReady := $config/@on-ready/string()
    return
        <jquery:script>
            var options = {{
                deleteTrigger: '{$delete}',
                onReady: { if ($onReady) then $onReady else 'new function() {}' }
            }};
            $('{$formSelector}').repeat('{$trigger}', options);
        </jquery:script>
};

(:~
    Toggles an HTML block upon the click on a link or button.
    The contents of the HTML block are retrieved via AJAX from
    the URL given in attribute "href".

<![CDATA[
        <jquery:toggle href="filters.xql?type=date"
            trigger="#filters li:nth-child(3) .expand"/>
    ]]>

href: the URL to load the HTML content block from

trigger: jQuery selector pointing to the trigger element
            on which the user should click

callback: optional callback javascript function which will
            be called once the contents of the toggle block are loaded.
            The function receives the trigger element as first parameter,
            the id of the toggle block as second.

:)
declare function jquery:toggle($config as element(jquery:toggle)) as element()+ {
    let $id0 := $config/@id/string()
    let $id := if ($id0) then $id0 else util:uuid()
    let $trigger := $config/@trigger/string()
    let $href := $config/@href/string()
    let $callback := $config/@callback/string()
    let $beforeCallback := $config/@beforeCallback/string()
    return (
        if (empty($id0)) then

        else (),
        <jquery:script>
            $('#{$id}').css('display', 'none');
            $('{$trigger}').click(function(ev) {{
                if ($(this).hasClass('expanded')) {{
                    $('#{$id}').css('display', 'none');
                }} else {{
                    var trigger = this;
                    {
                        if ($beforeCallback) then
                            jquery:script(<s>
                                var r = {$beforeCallback}.call(trigger, '{$id}');
                                if (!r) return false;
                            </s>)
                        else
                            ()
                    }
                    $('#{$id}').css('display', 'block');
                    {
                        if ($href) then
                            jquery:script(<s>$('#{$id}').load('{$href}', null, function() {{
                                {
                                    if ($callback) then
                                        concat($callback, ".call(trigger, '", $id, "');")
                                    else
                                        ()
                                }
                            }});</s>)
                        else
                            ()
                    }
                }}
                $(this).toggleClass('expanded');
                ev.preventDefault();
            }});
        </jquery:script>
    )
};

(:~
    <jquery:paginate id="results" attribute="results"
        href="retrieve" navcontainer="#results-head .navbar"/>
:)
declare function jquery:paginate($config as element(jquery:paginate)) as element()+ {
    let $hits := session:get-attribute($config/@attribute)
    let $id := if ($config/@id) then $config/@id/string() else util:uuid()
    let $onReady := $config/@on-ready/string()
    return (

,
        <jquery:script>
            $('#{$id}').pagination('{$config/@href/string()}', {{
                    totalItems: {count($hits)},
                    itemsPerPage: 10,
                    navContainer: '{$config/@navcontainer/string()}'
                    { if ($onReady) then (", readyCallback: ", $onReady) else () }
            }});
        </jquery:script>
    )
};

(:~
    Helper function for jquery:input-field()
:)
declare function jquery:extra-params($id as xs:string, $auto as element(jquery:autocomplete)) {
    if ($auto/jquery:param) then
        string-join(
            for $param in $auto/jquery:param
            return
                concat($param/@name, ': function () { ',
                    " return ", $param/@function, '.call($("#', $id, '"));}'),
            ', '
        )
    else
        ()
};

(:~
    Create an HTML input element. Copies all attributes of the jquery:input
    element. If no value attribute is present, the function will look up the
    parameter in the HTTP request, and if the parameter is set, add it as value
    attribute.

<![CDATA[<jquery:input name="input1"/>]]>

:)
declare function jquery:input-field($node as element(jquery:input)) as element()+ {
    let $name := $node/@name/string()
    let $id := if ($node/@id) then $node/@id/string() else util:uuid()
    return (
        if ($node/jquery:autocomplete) then
            let $auto := $node/jquery:autocomplete
            let $width := if ($auto/@width) then $auto/@width/string() else 200
            let $multiple := if ($auto/@multiple) then $auto/@multiple/string() else "false"
            let $matchContains := if ($auto/@matchContains) then $auto/@matchContains/string() else "false"
            let $minLength := if ($auto/@minLength) then $auto/@minLength/string() else "3"
            return
                <jquery:script>
                        $('#{$id}').autocomplete({{
                            source: function(request, response) {{
                                var data = {{ term: request.term }};
                                {
                                    for $cb in $auto/@paramsCallback
                                    return
                                        concat($cb, '($("#', $id, '"), data);')
                                }
                                $.ajax({{
                                    url: "{$auto/@url/string()}",
                                    dataType: "json",
                   					data: data,
                                    success: function(data) {{
                                        response(data);
                                    }}
                                }});
                            }},
                            minLength: { $minLength },
                            delay: 700
                        }});
                </jquery:script>
        else
            (),
        <input>
        { $node/@* }
        { if (empty($node/@id)) then attribute id { $id } else () }
        {
            if (empty($node/@value)) then
                attribute value { request:get-parameter($name, "") }
            else
                ()
        }
        </input>
    )
};

(:~
    { jquery:extra-params($id, $auto) }
                        width: { $width },
                        minChars: 3
    Create an HTML select element. Copies all attributes of the jquery:select
    element. jquery:select should contain zero or more jquery:option elements
    which are transformed into HTML option elements. Each option must have a
    value attribute and may have an optional text content. Both are copied to
    the generated HTML option.

    For each option, the HTTP request is checked for a corresponding parameter
    value. If present, the option will be selected.

<![CDATA[
        <jquery:select name="sort">
            <jquery:option value="Author"/>
            <jquery:option value="Title"/>
            <jquery:option value="Date Issued"/>
        </jquery:select>
    ]]>

:)
declare function jquery:select-field($node as element(jquery:select)) as element() {
    let $name := $node/@name/string()
    let $value := request:get-parameter($name, "")
    return
        <select>
        { $node/@* }
        {
            for $option in $node/jquery:option
            return
                <option>
                { $option/@value }
                { if ($option/@value eq $value) then attribute selected { "selected" } else () }
                { if ($option/text()) then $option/text() else $option/@value/string() }
                </option>
        }
        </select>
};

declare function jquery:button($node as element(jquery:button)) as element()+ {
    let $id := if ($node/@id) then $node/@id/string() else util:uuid()
    return (
        <button id="{$id}">{$node/@*[not(local-name(.) = 'id')], $node/node()}</button>,
        <jquery:script>
        $('#{$id}').button();
        </jquery:script>
    )
};

declare function jquery:accordion($config as element(jquery:ajax-accordion)) as element()+ {
    let $id := if ($config/@id) then $config/@id/string() else concat('N', util:uuid())
    let $panels :=
        for $panel in $config/jquery:panel
        let $panelId := if ($panel/@id) then $panel/@id/string() else concat('N', util:uuid())
        return

{$panel/@title/string()}

                {
                    if ($panel/node()) then
                        for $child in $panel/node() return
                            jquery:process-templates($child)
                    else

Loading ...

                }

    return (

        {   $config/@class, $panels/* }

,
        <jquery:script>
            var actions = {{}};
            {
                for $panel at $p in $config/jquery:panel
                return
                    if ($panel/@href) then
                        jquery:script(<s>actions["{$panels[$p]/h3/@id/string()}"] = "{$panel/@href/string()}";</s>)
                    else if ($panel/@on-select) then
                        jquery:script(<s>actions["{$panels[$p]/h3/@id/string()}"] = {$panel/@on-select/string()};</s>)
                    else ()
            }
            $('#{$id}').accordion({{
                autoHeight: { if ($config/@autoHeight eq "true") then "true" else "false" },
                fillSpace: { if ($config/@fillSpace eq "true") then "true" else "false" },
                collapsible: true,
                active: { if ($config/@active eq "true") then "true" else "false" },
                change: function (event, ui) {{
                    var id = ui.newHeader.attr('id');
                    var panel = ui.newHeader.next();
                    var action = actions[id];
                    if (typeof action == "function")
                        action.call();
                    else
                        panel.load(action);
                }}
            }});
        </jquery:script>
    )
};

declare function jquery:dialog($config as element(jquery:dialog)) as node()* {
    let $trigger := $config/@trigger
    let $id := $config/@id
    let $modal := $config/@modal = 'true'
    let $buttons :=
        string-join(
            for $button in $config/jquery:button
            return
                if ($button/@id eq 'cancel') then
                    string-join(('"', $button/@label, '": function() { $(this).dialog("close"); }'), "")
                else if ($button/@id eq 'submit') then
                    string-join(('"', $button/@label, '": function() { $("#', $id/string(), ' form").submit(); }'), "")
                else if ($button/@function) then
                    string-join(('"', $button/@label, '": function () { ', $button/@function, '($(this)); }'), "")
                else
                    string-join(('"', $button/@label, '": function() {', $button/node(), '}'), "")
            , ", ")
    return

            { $id, for $child in $config/*[not(self::jquery:*)] return jquery:process-templates($child) }
            <jquery:script>
                    $('#{$id/string()}').dialog({{
                        modal: { if ($modal) then 'true' else 'false' },
                        autoOpen: false,
                        {
                            if($config/@onOpen)then(
                                fn:concat("open: function(event, ui){ ",  string($config/@onOpen), "(); },")
                            )else()
                        }
                        buttons: {{ { $buttons } }}
                        {
                            let $attribs :=
                                for $attr in $config/@*
                                return
                                    if ($attr/local-name() = ("height", "minHeight", "maxHeight",
                                        "minWidth", "maxWidth", "width")) then
                                        concat($attr/local-name(), ": ", $attr/string())
                                    else if ($attr/local-name() = ("title", "position",
                                        "dialogClass", "closeText")) then
                                        concat($attr/local-name(), ': "', $attr/string(), '"')
                                    else
                                        ()
                            return
                                if (exists($attribs)) then
                                    concat(", ", string-join($attribs, ", "))
                                else
                                    ()
                        }
                    }});
            </jquery:script>
            {
                if($trigger)then
                (
                    <jquery:script>
                        var trigger = '{$trigger/string()}';
                        if (trigger != '')
                            $(trigger).click(function() {{
                                $('#{$id/string()}').dialog('open');
                                return false;
                            }});
                    </jquery:script>
                )else()
            }

};

declare function jquery:escape-xml($node as node()) as xs:string* {
    typeswitch ($node)
        case element() return
            string-join(
                (
                    "<", node-name($node),
                    for $attr in $node/@* return concat(" ", node-name($attr), '="', $attr/string(), '"'),
                    if ($node/node()) then
                        (">", for $child in $node/node() return jquery:escape-xml($child), "</", node-name($node), ">")
                    else
                        "/>"
                ),
                ""
            )
        default return
            $node
};

declare function jquery:source($node as node()) as node()* {
    let $id := $node/@ref
    let $code := root($node)//*[@id = $id][1]
    return

            { jquery:escape-xml($code) }

};

(:~
    Main function to process an HTML template. All jquery:* elements
    in the template are expanded, if known.
:)
declare function jquery:process-templates($node as node()) as node()* {
    typeswitch ($node)
        case element(jquery:form-repeat) return
            jquery:form-repeat($node)
        case element(jquery:tabset) return
            jquery:tabset($node)
        case element(jquery:toggle) return
            jquery:toggle($node)
        case element(jquery:paginate) return
            jquery:paginate($node)
        case element(jquery:input) return
            jquery:input-field($node)
        case element(jquery:select) return
            jquery:select-field($node)
        case element(jquery:button) return
            jquery:button($node)
        case element(jquery:ajax-accordion) return
            jquery:accordion($node)
        case element(jquery:dialog) return
            jquery:dialog($node)
        case element(jquery:header) return
            jquery:header($node)
        case element(jquery:source) return
            jquery:source($node)
        case element() return
            element { node-name($node) } {
                $node/@*,
                for $child in $node/node()
                return
                    jquery:process-templates($child)
            }
        default return
            $node
};

declare function jquery:process($node as node()) as node()* {
     jquery:cleanup-javascript(
        jquery:process-templates($node)
    )
};

declare function jquery:cleanup-javascript($node as node(), $scripts as element()*) {
    typeswitch ($node)
        case element(body) return
            {
                $node/@*,
                for $child in $node/node() return jquery:cleanup-javascript($child, $scripts),

            }
        case element(jquery:script) return
            ()
        case element() return
            element { node-name($node) } {
                $node/@*,
                for $child in $node/node() return jquery:cleanup-javascript($child, $scripts)
            }
        default return
            $node
};

declare function jquery:cleanup-javascript($root as element()) {
    let $scripts := $root//jquery:script
    return
        jquery:cleanup-javascript($root, $scripts)
};


put variadic annotation of index dml into the zorba annotation namespace

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

(:~
 : This module defines a set of functions to probe indexes.
 :
 : @see http://www.zorba-xquery.com/modules/store/static/collections/ddl
 : @see http://www.zorba-xquery.com/modules/store/static/indexes/ddl
 : @see http://www.zorba-xquery.com/modules/store/static/indexes/dml
 :
 : @author Nicolae Brinza, Matthias Brantner, David Graf, Till Westmann, Markos Zaharioudakis
 : @project store/indexes/static
 :
 : @project store/indexes
 :
 :)
module namespace dml = "http://www.zorba-xquery.com/modules/store/static/indexes/dml";

declare namespace ann = "http://www.zorba-xquery.com/annotations";

(:~
 : The probe function retrieves the domain nodes associated with a particular
 : search condition, which is presented as a single key tuple. This function
 : accept a variable number of arguments.
 :
 :   dml:probe-index-point($indexUri as xs:QName,
 :                        $key1     as xs:anyAtomictType,
 :                        ...,
 :                        $keyM     as xs:anyAtomicType) as node()*
 :
 : The first argument is always a QName identifying an index. The rest of the
 : arguments specify the search condition, which is given as a number of
 : atomic items comprising a key tuple. This number must be equal to the number
 : of indexspecs found in the index declaration [err:XDDY0025]. If the index
 : contains an entry with the given key tuple, the associated domain nodes are
 : returned. Otherwise, the empty sequence is returned.
 :
 : @param $name The QName of the index.
 : @param $key1 The search condition.
 : @return The sequence of domain nodes or an empty sequence.
 : @error If available indexes does not provide a mapping for
 :        the expanded QName $name.
 :)
declare %ann:variadic function dml:probe-index-point-value(
  $name as xs:QName,
  $key1 as xs:anyAtomicType*) as node()*  external;

(:~
 : The probe function retrieves the domain nodes associated with a particular
 : search condition, which is presented as a range of key tuples. This function
 : accept a variable number of arguments.
 :
 : dml:probe-index-range($indexUri                 as xs:QName,
 :                         $rangeLowerBound1         as xs:anyAtomicType?,
 :                         $rangeUpperBound1         as xs:anyAtomicType?,
 :                         $rangeHaveLowerBound1     as xs:boolean,
 :                         $rangeHaveupperBound1     as xs:boolean,
 :                         $rangeLowerBoundIncluded1 as xs:boolean,
 :                         $rangeupperBoundIncluded1 as xs:boolean,
 :                         ....,
 :                         $rangeLowerBoundM         as xs:anyAtomicType?,
 :                         $rangeUpperBoundM         as xs:anyAtomicType?,
 :                         $rangeHaveLowerBoundM     as xs:boolean,
 :                         $rangeHaveupperBoundM     as xs:boolean,
 :                         $rangeLowerBoundIncludedM as xs:boolean,
 :                         $rangeupperBoundIncludedM as xs:boolean) as node()*
 :
 : To describe the semantics of this function, we start by defining the i-th
 : key column of an index as the set of key items produced by evaluating the
 : i-th keyspec of the index for every domain node. Then, the search condition
 : of a range probe can be defined as a number of rangespecs, where a
 : rangespec describes a constraint on the values of a key column. The first
 : rangespec applies to the first key column, the second rangespec to the
 : second key column, etc. The number of rangespecs must be less or equal to
 : the number of keyspecs found in the declaration of the given index.
 : Each rangespec consists of 6 values:
 :
 :   * rangeLowerBound : The lower bound in a range of key values.
 :   * rangeUpperBound : The upper bound in a range of key values.
 :   * rangeHaveLowerBound : If false, then there is no lower bound, or
 :     equivalently, the lower bound is -INFINITY (the actual rangeLowerBound
 :     value is ignored). Otherwise, the lower bound is the one given by the
 :     rangeLowerBound value. The effective lower bound of the range is either
 :     the rangeLowerBound if rangeHaveLowerBound is true, or -INFINITY if
 :     rangeHaveLowerBound is false.
 :   * rangeHaveUpperBound : If false, then there is no upper bound, or
 :     equivalently, the upper bound is +INFINITY (the actual rangeUpperBound
 :     value is ignored). Otherwise, the upper bound is the one given by the
 :     rangeUpperBound value. The effective upper bound of the range is either
 :     the rangeUpperBound if rangeHaveUpperBound is true, or +INFINITY if
 :     rangeHaveUpperBound is false.
 :   * rangeLowerBoundIncluded : If false, then the range is open from below,
 :     i.e., the rangeLowerBound value is not considered part of the range.
 :     Otherwise, the range is closed from below, i.e., the rangeLowerBound
 :     value is part of the range.
 :   * rangeUpperBoundIncluded : If false, then the range is open from above,
 :     i.e., the rangeUpperBound value is not considered part of the range.
 :     Otherwise, the range is closed from above, i.e., the rangeUpperBound
 :     value is part of the range.
 :
 : @param $name The QName of the index.
 : @param $rangeLowerBound1 The lower bound in a range of key values.
 : @param $rangeUpperBound1 The upper bound in a range of key values.
 : @param $rangeHaveLowerBound If false, then there is no lower bound, or
 :          equivalently, the lower bound is -INFINITY. Otherwise, the lower
 :          bound is the one given by the rangeLowerBound value.
 : @param $rangeHaveUpperBound If false, then there is no upper bound, or
 :          equivalently, the upper bound is +INFINITY. Otherwise, the upper
 :          bound is the one given by the rangeUpperBound value.
 : @param $rangeLowerBoundIncluded If false, then the range is open from below,
 :          i.e., the rangeLowerBound value is not considered part of the
 :          range. Otherwise, the range is closed from below, i.e., the
 :          rangeLowerBound value is part of the range.
 : @param $rangeUpperBoundIncluded If false, then the range is open from above,
 :          i.e., the rangeUpperBound value is not considered part of the
 :          range. Otherwise, the range is closed from above, i.e., the
 :          rangeUpperBound value is part of the range.
 : @return The sequence of domain nodes.
 : @error If available indexes does not provide a mapping for
 :        the expanded QName $name.
 :)
declare %ann:variadic function dml:probe-index-range-value($name as xs:QName,
  $rangeLowerBound1         as xs:anyAtomicType?,
  $rangeUpperBound1         as xs:anyAtomicType?,
  $rangeHaveLowerBound1     as xs:boolean,
  $rangeHaveupperBound1     as xs:boolean,
  $rangeLowerBoundIncluded1 as xs:boolean,
  $rangeupperBoundIncluded1 as xs:boolean) as node()*  external;

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

(:~
 : This module defines a set of functions to probe indexes.
 :
 : @see http://www.zorba-xquery.com/modules/store/static/collections/ddl
 : @see http://www.zorba-xquery.com/modules/store/static/indexes/ddl
 : @see http://www.zorba-xquery.com/modules/store/static/indexes/dml
 :
 : @author Nicolae Brinza, Matthias Brantner, David Graf, Till Westmann, Markos Zaharioudakis
 : @project store/indexes/static
 :
 : @project store/indexes
 :
 :)
module namespace dml = "http://www.zorba-xquery.com/modules/store/static/indexes/dml";

(:~
 : The probe function retrieves the domain nodes associated with a particular
 : search condition, which is presented as a single key tuple. This function
 : accept a variable number of arguments.
 :
 :   dml:probe-index-point($indexUri as xs:QName,
 :                        $key1     as xs:anyAtomictType,
 :                        ...,
 :                        $keyM     as xs:anyAtomicType) as node()*
 :
 : The first argument is always a QName identifying an index. The rest of the
 : arguments specify the search condition, which is given as a number of
 : atomic items comprising a key tuple. This number must be equal to the number
 : of indexspecs found in the index declaration [err:XDDY0025]. If the index
 : contains an entry with the given key tuple, the associated domain nodes are
 : returned. Otherwise, the empty sequence is returned.
 :
 : @param $name The QName of the index.
 : @param $key1 The search condition.
 : @return The sequence of domain nodes or an empty sequence.
 : @error If available indexes does not provide a mapping for
 :        the expanded QName $name.
 :)
declare %variadic function dml:probe-index-point-value(
  $name as xs:QName,
  $key1 as xs:anyAtomicType*) as node()*  external;

(:~
 : The probe function retrieves the domain nodes associated with a particular
 : search condition, which is presented as a range of key tuples. This function
 : accept a variable number of arguments.
 :
 : dml:probe-index-range($indexUri                 as xs:QName,
 :                         $rangeLowerBound1         as xs:anyAtomicType?,
 :                         $rangeUpperBound1         as xs:anyAtomicType?,
 :                         $rangeHaveLowerBound1     as xs:boolean,
 :                         $rangeHaveupperBound1     as xs:boolean,
 :                         $rangeLowerBoundIncluded1 as xs:boolean,
 :                         $rangeupperBoundIncluded1 as xs:boolean,
 :                         ....,
 :                         $rangeLowerBoundM         as xs:anyAtomicType?,
 :                         $rangeUpperBoundM         as xs:anyAtomicType?,
 :                         $rangeHaveLowerBoundM     as xs:boolean,
 :                         $rangeHaveupperBoundM     as xs:boolean,
 :                         $rangeLowerBoundIncludedM as xs:boolean,
 :                         $rangeupperBoundIncludedM as xs:boolean) as node()*
 :
 : To describe the semantics of this function, we start by defining the i-th
 : key column of an index as the set of key items produced by evaluating the
 : i-th keyspec of the index for every domain node. Then, the search condition
 : of a range probe can be defined as a number of rangespecs, where a
 : rangespec describes a constraint on the values of a key column. The first
 : rangespec applies to the first key column, the second rangespec to the
 : second key column, etc. The number of rangespecs must be less or equal to
 : the number of keyspecs found in the declaration of the given index.
 : Each rangespec consists of 6 values:
 :
 :   * rangeLowerBound : The lower bound in a range of key values.
 :   * rangeUpperBound : The upper bound in a range of key values.
 :   * rangeHaveLowerBound : If false, then there is no lower bound, or
 :     equivalently, the lower bound is -INFINITY (the actual rangeLowerBound
 :     value is ignored). Otherwise, the lower bound is the one given by the
 :     rangeLowerBound value. The effective lower bound of the range is either
 :     the rangeLowerBound if rangeHaveLowerBound is true, or -INFINITY if
 :     rangeHaveLowerBound is false.
 :   * rangeHaveUpperBound : If false, then there is no upper bound, or
 :     equivalently, the upper bound is +INFINITY (the actual rangeUpperBound
 :     value is ignored). Otherwise, the upper bound is the one given by the
 :     rangeUpperBound value. The effective upper bound of the range is either
 :     the rangeUpperBound if rangeHaveUpperBound is true, or +INFINITY if
 :     rangeHaveUpperBound is false.
 :   * rangeLowerBoundIncluded : If false, then the range is open from below,
 :     i.e., the rangeLowerBound value is not considered part of the range.
 :     Otherwise, the range is closed from below, i.e., the rangeLowerBound
 :     value is part of the range.
 :   * rangeUpperBoundIncluded : If false, then the range is open from above,
 :     i.e., the rangeUpperBound value is not considered part of the range.
 :     Otherwise, the range is closed from above, i.e., the rangeUpperBound
 :     value is part of the range.
 :
 : @param $name The QName of the index.
 : @param $rangeLowerBound1 The lower bound in a range of key values.
 : @param $rangeUpperBound1 The upper bound in a range of key values.
 : @param $rangeHaveLowerBound If false, then there is no lower bound, or
 :          equivalently, the lower bound is -INFINITY. Otherwise, the lower
 :          bound is the one given by the rangeLowerBound value.
 : @param $rangeHaveUpperBound If false, then there is no upper bound, or
 :          equivalently, the upper bound is +INFINITY. Otherwise, the upper
 :          bound is the one given by the rangeUpperBound value.
 : @param $rangeLowerBoundIncluded If false, then the range is open from below,
 :          i.e., the rangeLowerBound value is not considered part of the
 :          range. Otherwise, the range is closed from below, i.e., the
 :          rangeLowerBound value is part of the range.
 : @param $rangeUpperBoundIncluded If false, then the range is open from above,
 :          i.e., the rangeUpperBound value is not considered part of the
 :          range. Otherwise, the range is closed from above, i.e., the
 :          rangeUpperBound value is part of the range.
 : @return The sequence of domain nodes.
 : @error If available indexes does not provide a mapping for
 :        the expanded QName $name.
 :)
declare %variadic function dml:probe-index-range-value($name as xs:QName,
  $rangeLowerBound1         as xs:anyAtomicType?,
  $rangeUpperBound1         as xs:anyAtomicType?,
  $rangeHaveLowerBound1     as xs:boolean,
  $rangeHaveupperBound1     as xs:boolean,
  $rangeLowerBoundIncluded1 as xs:boolean,
  $rangeupperBoundIncluded1 as xs:boolean) as node()*  external;


fixed a typo in the documentation

fixed a typo in the documentation

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

(:~
 :

 : This module provides an implementation of the
 : EXPath Http Client.
 : It provides functions for making HTTP requests and is a superset of the
 : module specified by EXPath.
 : Specifically, it implements the http:send-request() functions
 : as specified by EXPath. Moreover, it adds an additional function
 : http:read() (with several arities for the sake of ease).
 :

 :
 :

 : In general, both functions take a description of the HTTP request to make
 : as parameter, execute the request, and return a representation of the HTTP
 : response.
 :

 :
 :

 : The http:send-request() functions are declared as sequential.
 : Sequential functions are allowed to have side effects. For example, most probably,
 : an HTTP POST request is a request that has side effects because it adds/changes
 : a remote resource. Such functions are an extension of XQuery and are specified in
 : the XQuery Scripting Extension.
 : Sequential functions are only allowed to be invoked in certain places (e.g.
 : only from functions which are declared as sequential themselves).
 : In contrast, the http:read() functions are declared as
 : nondeterministic (see XQuery 1.1).
 : HTTP requests performed using these functions are not allowed to have
 : side effects.
 :

 :
 :

 : For almost all functions (except read with one parameter),
 : the request is represented by an http:request
 : element, specifying the URI, the HTTP method, the headers, and the body
 : content (for POST and PUT methods) of the HTTP request to make.
 :

 :
 :

 : The response is returned as a sequence of one or more items. The first
 : one is an http:response element with quite the same
 : structure as an http:request, but without the content itself.
 : The content is returned as the second item (or several items in case of
 : a multipart response) as a string, a document node, or a binary item.
 : This depends on the content-type returned.
 : Specifically, the rules are as follows:
 :
 :

 :
A document node is returned if the media type has a MIME type of
 :     text/xml, application/xml, text/xml-external-parsed-entity, or
 :     application/xml-external-parsed-entity, as defined in [RFC 3023]
 :     (except that application/xml-dtd is considered a text media type).
 :     MIME types ending by +xml are also XML media types.

 :
A document node is returned if the media type has a MIME type of
 :      text/html. In order to be able to make HTML parseable, tidy is automatically
 :      invoked. If you want to prevent that, you can also set your own content-type
 :      by setting the override-media-type attribute in the request element.
 :       For tidying, the following options
 :       will be used:
 :

 :
TidyXmlOut=yes

 :
TidyDoctypeMode=TidyDoctypeOmit

 :
TidyQuoteNbsp=yes

 :
TidyCharEncoding="utf8"

 :
TidyNewline="LF"

 :

 :

 :
A xs:string item is returned if the media type has a text MIME type,
 :     i.e. beginning with text/.

 :
A xs:base64Binary item is returned for all the other media types.

 :

 :

 :
 : Simple GET Request (retrieving HTML)
 :
 :
 :

 :   http:read( <http:request href="www.example.com" method="get"/>, () )
 :

 :
 :
 : returns
 :
 :
 :

 :   <response xmlns="http://expath.org/ns/http-client" status="200" message="OK">
 :     <header name="Content-Type" value="text/html; charset=UTF-8"/>
 :     <header name="Content-Length" value="574"/>
 :     ...
 :     <body media-type="text/html"/>
 :   </response>
 :   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 :   <html>
 :     <head>
 :       <meta http-equiv="Content-Type"
 :       content="text/html; charset=utf-8" />
 :       <title>Example Web Page</title>
 :     </head>
 :     <body>
 :       <p>You have reached this web page by typing "example.com",
 :       "example.net", or "example.org" into your web browser.</p>
 :       <p>These domain names are reserved for use in documentation and are
 :       Not available for registration. See
 :       <a href="http://www.rfc-editor.org/rfc/rfc2606.txt">RFC 2606</a>,
 :       Section 3.</p>
 :     </body>
 :   </html>
 :

 :
 :
 : Simple GET Request (retrieving XHTML)
 :
 :
 :

 :   declare namespace xhtml="http://www.w3.org/1999/xhtml";
 :
 :   http:read( <http:request href="www.w3.org" method="get"/>, () )[2]//xhtml:body
 :

 :
 :
 :

 : This example shows how to retrieve an XHTML resource. Note, that the node test
 : that is looking for the body element in the result requires the xhtml
 : namespace to be specified.
 :

 :
 : Simple POST Request
 :
 :

 : Here is a simple example which sends a text content by making an HTTP POST
 : request.
 :

 :
 :
 :

 :   http:send-request(
 :      <http:request href="..." method="post">
 :         <http:body content-type="text/plain">
 :            Hello, world!
 :         </http:body>
 :      </http:request>
 :   )
 :

 :
 :
 : The response of this request can look as follows:
 :
 :

 :
 :   <http:response status="200" message="Ok">
 :      <http:header name="Content-Type" value="text/html"/>
 :      <http:header name="Server" value="Apache ..."/>
 :      ...
 :      <http:body content-type="text/html"/>
 :   </http:response>
 :
 :

 :
 :

 : The structure of a request element is defined in the schema that is imported
 : by this module. The details are described in the
 : specification.
 : Analogously, the response element is also described in this
 : specification.
 :

 :
 : @author Markus Pilman
 :)
module namespace http = "http://expath.org/ns/http-client";

import module namespace httpclientimpl = "http://expath.org/ns/httpclientimpl";
import module namespace err = "http://expath.org/ns/error";

import schema namespace https = "http://expath.org/ns/http-client";

(:~
 : This function sends an HTTP request and returns the corresponding response.
 :
 :

 : This function is declared as sequential (see XQuery Scripting).
 : Sequential functions are allowed to have side effects. For example, most probably,
 : an HTTP POST request is a request that has side effects because it adds/changes
 : a remote resource.
 :

 :
 : @param $request Contains the various parameters of the request.
 :   See the
 :   specification.
 :   for a full description of the structure of this element.
 : @param $href is the HTTP or HTTPS URI to send the request to. It must be a valid
 :  xs:anyURI, but is declared as a string to be able to pass literal strings
 :  (without requiring to explicitly cast it to an xs:anyURI.)
 : @param $content is the request body content, for HTTP methods that can
 :  contain a body in the request (i.e. POST and PUT). It is an error, if this
 :  param is not the empty sequence for methods other then DELETE, GET, HEAD
 :  and OPTIONS.
 : @return a sequence of items, where the first item is a element of type
 :  http:responseType. The response element is also described in the
 :  specification.
 :  If there is one (or several, in case of multipart) response body, the response bodies
 :  are the next items in the sequence.
 :)
declare sequential function http:send-request(
  $request as element(https:request)?,
  $href as xs:string?,
  $bodies as item()*) as item()+ {
  if (http:check-params($request, $href, $bodies))
  then
    let $req := if ($request) then validate { http:set-content-type($request) } else ()
    let $result := httpclientimpl:http-send-request-impl($req,
                                                         $href,
                                                         $bodies)
    return (validate {$result[1]}, fn:subsequence($result, 2))
  else ()
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the send-request function
 : as follows:
 :
 :
 : http:send-request($request, (), ())
 :
 :
 : @see documentation of send-request with three parameters.
 :
 : @param $request see request parameter of the sequential
 :  send-request function with three parameters.
 : @return see return value of the sequential
 :  send-request function with three parameters.
 :)
declare sequential function http:send-request (
  $request as element(https:request)) as item()+ {
  http:send-request($request, (), ())
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the send-request function
 : as follows:
 :
 :
 : http:send-request($request, $href, ())
 :
 :
 : @see documentation of send-request with three parameters.
 :
 : @param $request see request parameter of the sequential
 :  send-request function with three parameters.
 : @param $href see href parameter of the sequential
 :  send-request function with three parameters.
 : @return see return of
 :  send-request
 :)
declare sequential function http:send-request(
  $request as element(https:request)?,
  $href as xs:string?) as item()+ {
  http:send-request($request, $href, ())
};

(:~
 : This function sends an HTTP request and returns the corresponding response.
 :
 :

 : This function is not sequential. Usually, this function should be used
 : for retrieving resources using HTTP GET or HEAD (i.e. HTTP requests which
 : are known to not have any side effects.
 :

 :
 : @param $request Contains the various parameters of the request.
 :   See the
 :   specification.
 :   for a full description of the structure of this element.
 : @param $href is the HTTP or HTTPS URI to send the request to. It must be a valid
 :  xs:anyURI, but is declared as a string to be able to pass literal strings
 :  (without requiring to explicitly cast it to an xs:anyURI.)
 : @param $bodies is the request body content, for HTTP methods that can
 :  contain a body in the request (i.e. POST and PUT). It is an error, if this
 :  param is not the empty sequence for methods other then DELETE, GET, HEAD
 :  and OPTIONS.
 : @return a sequence of items, where the first item is a element of type
 :  http:responseType. The response element is also described in the
 :  specification.
 :  If there is one (or several, in case of multipart) response body, the response bodies
 :  are the next items in the sequence.
 :)
declare function http:read(
  $request as element(https:request)?,
  $href as xs:string?,
  $bodies as item()*) as item()+ {
  if (http:check-params($request, $href, $bodies))
  then
    let $req := if ($request) then validate { http:set-content-type($request) } else ()
    let $result := httpclientimpl:http-read-impl($req, $href, $bodies)
    return (validate {$result[1]}, fn:subsequence($result, 2))
  else ()
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the read function as follows:
 :
 :
 : http:read($request, $href, ())
 :
 :
 : @see documentation of read
 :      with three parameters.
 :
 : @param $request see parameter $request of read with three parameters
 : @param $href see parameter $href of read with three parameters
 : @return see return of read with three parameters
 :)
declare function http:read(
  $request as element(https:request)?,
  $href as xs:string?) as item()+ {
  http:read($request, $href, ())
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the read function
 : as follows:
 :
 :
 : http:read((), $href, ())
 :
 :
 : @see documentation of read with three parameters.
 :
 : @param $href see parameter $href of read with three parameters
 : @return see return of read with three parameters
 :)
declare function http:read(
  $href as xs:string) as item()+ {
  http:read((), $href, ())
};

(:~
 : Helper function.
 :
 : This function takes an https:body element, copies it, and
 : adds a method attribute to the copy if there is none
 : in the original element.
 :
 : @param $body is the original https:body element
 : @return a https:body element with a corresponding @method
 :   attribute
 :)
declare function http:create-body (
  $body as element(https:body))
    as element(https:body) {
  <https:body>{$body/@*}
  {
    if ($body/@method) then
      ()
    else
      attribute method {
        if ($body/@media-type eq "text/xml" or
            $body/@media-type eq "application/xml" or
            $body/@media-type eq "text/xml-external-parsed-entity" or
            $body/@media-type eq "application/xml-external-parsed-entity") then
              "xml"
         else if ($body/@media-type eq "text/html") then "html"
         else if (fn:starts-with($body/@media-type/data(.), "text/")) then "text"
         else "binary"
      }
  }
  {$body/node()}
  </https:body>
};

(:~
 : Helper function.
 :
 : This function takes an https:multipart element, copies it and
 : adds a @method attribute to all body elements which don't have
 : one.
 :
 : @param $multipart the original https:multipart
 : @return a copy of $multipart with all $multipart/body/@method set
 :)
declare function http:create-multipart (
  $multipart as element(https:multipart))
    as element(https:multipart) {
  validate {
    <https:multipart>{$multipart/@*}
    {
    for $x in $multipart/node()
    return
      typeswitch($x)
        case element(https:body) return http:create-body($x)
        default return $x
    }
    </https:multipart>
  }
};

(:~
 : Helper function.
 :
 : This adds a default method attribute to all body elements which
 : don't contain a method attribute.
 :
 : @param $request The request which need to be copied.
 : @return A copy of $request with all request//body/@method set.
 :)
declare function http:set-content-type(
  $request as element(https:request)?)
    as element(https:request)? {
  if ($request) then
    validate
    {
      <http:request>{$request/@*}
      {
      for $x in $request/node()
      return
        typeswitch($x)
          case element(https:body) return http:create-body($x)
          case element(https:multipart) return http:create-multipart($x)
          default return $x
      }
      </http:request>
    }
  else ()
};

(:~
 : Private helper function used internally by this module.
 :
 : This function checks if the request, href, and bodies parameters
 : are consistent.
 :
 : @param $request The request which needs to be checked.
 : @param $href The href which needs to be checked.
 : @param $bodies The bodies element which needs to be checked.
 : @return true if the parameters are consistent. Otherwise,
 :         this function raises an error.
 :)
declare function http:check-params(
  $request as element(https:request)?,
  $href as xs:string?,
  $bodies as item()*) as xs:boolean {
  if (fn:empty($href) and fn:empty($request)) then
    fn:error($err:HCV01, "Not all required arguments are set.")
  else if ($href eq "") then
    fn:error($err:HCV01,
      "The href value is set to the empty string")
  else if (not(count($request//body[not(exists(node()))]) eq count($bodies))) then
    fn:error($err:HCV01,
      "The number of bodies without children is not equal the size of the bodies sequence")
  else
    fn:true()
};

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

(:~
 :

 : This module provides an implementation of the
 : EXPath Http Client.
 : It provides functions for making HTTP requests and is a superset of the
 : module specified by EXPath.
 : Specifically, it implements the http:send-request() functions
 : as specified by EXPath. Moreover, it adds an additional function
 : http:read() (with several arities for the sake of ease).
 :

 :
 :

 : In general, both functions take a description of the HTTP request to make
 : as parameter, execute the request, and return a representation of the HTTP
 : response.
 :

 :
 :

 : The http:send-request() functions are declared as sequential.
 : Sequential functions are allowed to have side effects. For example, most probably,
 : an HTTP POST request is a request that has side effects because it adds/changes
 : a remote resource. Such functions are an extension of XQuery and are specified in
 : the XQuery Scripting Extension.
 : Sequential functions are only allowed to be invoked in certain places (e.g.
 : only from functions which are declared as sequential themselves).
 : In contrast, the http:read() functions are declared as
 : nondeterministic (see XQuery 1.1).
 : HTTP requests performed using these functions are not allowed to have
 : side effects.
 :

 :
 :

 : For almost all functions (except read with one parameter),
 : the request is represented by an http:request
 : element, specifying the URI, the HTTP method, the headers, and the body
 : content (for POST and PUT methods) of the HTTP request to make.
 :

 :
 :

 : The response is returned as a sequence of one or more items. The first
 : one is an http:response element with quite the same
 : structure as an http:request, but without the content itself.
 : The content is returned as the second item (or several items in case of
 : a multipart response) as a string, a document node, or a binary item.
 : This depends on the content-type returned.
 : Specifically, the rules are as follows:
 :
 :

 :
A document node is returned if the media type has a MIME type of
 :     text/xml, application/xml, text/xml-external-parsed-entity, or
 :     application/xml-external-parsed-entity, as defined in [RFC 3023]
 :     (except that application/xml-dtd is considered a text media type).
 :     MIME types ending by +xml are also XML media types.

 :
A document node is returned if the media type has a MIME type of
 :      text/html. In order to be able to make HTML parseable, tidy is automatically
 :      invoked. If you want to prevent that, you can also set your own content-type
 :      by setting the override-media-type attribute in the request element.
 :       For tidying, the following options
 :       will be used:
 :

 :
TidyXmlOut=yes

 :
TidyDoctypeMode=TidyDoctypeOmit

 :
TidyQuoteNbsp=yes

 :
TidyCharEncoding="utf8"

 :
TidyNewline="LF"

 :

 :

 :
A xs:string item is returned if the media type has a text MIME type,
 :     i.e. beginning with text/.

 :
A xs:base64Binary item is returned for all the other media types.

 :

 :

 :
 : Simple GET Request (retrieving HTML)
 :
 :
 :

 :   http:read( <http:request href="www.example.com" method="get"/>, () )
 :

 :
 :
 : returns
 :
 :
 :

 :   <response xmlns="http://expath.org/ns/http-client" status="200" message="OK">
 :     <header name="Content-Type" value="text/html; charset=UTF-8"/>
 :     <header name="Content-Length" value="574"/>
 :     ...
 :     <body media-type="text/html"/>
 :   </response>
 :   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 :   <html>
 :     <head>
 :       <meta http-equiv="Content-Type"
 :       content="text/html; charset=utf-8" />
 :       <title>Example Web Page</title>
 :     </head>
 :     <body>
 :       <p>You have reached this web page by typing "example.com",
 :       "example.net", or "example.org" into your web browser.</p>
 :       <p>These domain names are reserved for use in documentation and are
 :       Not available for registration. See
 :       <a href="http://www.rfc-editor.org/rfc/rfc2606.txt">RFC 2606</a>,
 :       Section 3.</p>
 :     </body>
 :   </html>
 :

 :
 :
 : Simple GET Request (retrieving XHTML)
 :
 :
 :

 :   declare namespace xhtml="http://www.w3.org/1999/xhtml";
 :
 :   http:read( <http:request href="www.w3.org" method="get"/>, () )[2]//xhtml:body
 :

 :
 :
 :

 : This example shows how to retrieve an XHTML resource. Note, that the node test
 : that is looking for the body element in the result requires the xhtml
 : namespace to be specified.
 :

 :
 : Simple POST Request
 :
 :

 : Here is a simple example which sends a text content by making an HTTP POST
 : request.
 :

 :
 :
 :

 :   http:send-request(
 :      http:request href="..." method="post">
 :         <http:body content-type="text/plain">
 :            Hello, world!
 :         </http:body>
 :      </http:request>
 :   )
 :

 :
 :
 : The response of this request can look as follows:
 :
 :

 :
 :   <http:response status="200" message="Ok">
 :      <http:header name="Content-Type" value="text/html"/>
 :      <http:header name="Server" value="Apache ..."/>
 :      ...
 :      <http:body content-type="text/html"/>
 :   </http:response>
 :
 :

 :
 :

 : The structure of a request element is defined in the schema that is imported
 : by this module. The details are described in the
 : specification.
 : Analogously, the response element is also described in this
 : specification.
 :

 :
 : @author Markus Pilman
 :)
module namespace http = "http://expath.org/ns/http-client";

import module namespace httpclientimpl = "http://expath.org/ns/httpclientimpl";
import module namespace err = "http://expath.org/ns/error";

import schema namespace https = "http://expath.org/ns/http-client";

(:~
 : This function sends an HTTP request and returns the corresponding response.
 :
 :

 : This function is declared as sequential (see XQuery Scripting).
 : Sequential functions are allowed to have side effects. For example, most probably,
 : an HTTP POST request is a request that has side effects because it adds/changes
 : a remote resource.
 :

 :
 : @param $request Contains the various parameters of the request.
 :   See the
 :   specification.
 :   for a full description of the structure of this element.
 : @param $href is the HTTP or HTTPS URI to send the request to. It must be a valid
 :  xs:anyURI, but is declared as a string to be able to pass literal strings
 :  (without requiring to explicitly cast it to an xs:anyURI.)
 : @param $content is the request body content, for HTTP methods that can
 :  contain a body in the request (i.e. POST and PUT). It is an error, if this
 :  param is not the empty sequence for methods other then DELETE, GET, HEAD
 :  and OPTIONS.
 : @return a sequence of items, where the first item is a element of type
 :  http:responseType. The response element is also described in the
 :  specification.
 :  If there is one (or several, in case of multipart) response body, the response bodies
 :  are the next items in the sequence.
 :)
declare sequential function http:send-request(
  $request as element(https:request)?,
  $href as xs:string?,
  $bodies as item()*) as item()+ {
  if (http:check-params($request, $href, $bodies))
  then
    let $req := if ($request) then validate { http:set-content-type($request) } else ()
    let $result := httpclientimpl:http-send-request-impl($req,
                                                         $href,
                                                         $bodies)
    return (validate {$result[1]}, fn:subsequence($result, 2))
  else ()
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the send-request function
 : as follows:
 :
 :
 : http:send-request($request, (), ())
 :
 :
 : @see documentation of send-request with three parameters.
 :
 : @param $request see request parameter of the sequential
 :  send-request function with three parameters.
 : @return see return value of the sequential
 :  send-request function with three parameters.
 :)
declare sequential function http:send-request (
  $request as element(https:request)) as item()+ {
  http:send-request($request, (), ())
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the send-request function
 : as follows:
 :
 :
 : http:send-request($request, $href, ())
 :
 :
 : @see documentation of send-request with three parameters.
 :
 : @param $request see request parameter of the sequential
 :  send-request function with three parameters.
 : @param $href see href parameter of the sequential
 :  send-request function with three parameters.
 : @return see return of
 :  send-request
 :)
declare sequential function http:send-request(
  $request as element(https:request)?,
  $href as xs:string?) as item()+ {
  http:send-request($request, $href, ())
};

(:~
 : This function sends an HTTP request and returns the corresponding response.
 :
 :

 : This function is not sequential. Usually, this function should be used
 : for retrieving resources using HTTP GET or HEAD (i.e. HTTP requests which
 : are known to not have any side effects.
 :

 :
 : @param $request Contains the various parameters of the request.
 :   See the
 :   specification.
 :   for a full description of the structure of this element.
 : @param $href is the HTTP or HTTPS URI to send the request to. It must be a valid
 :  xs:anyURI, but is declared as a string to be able to pass literal strings
 :  (without requiring to explicitly cast it to an xs:anyURI.)
 : @param $bodies is the request body content, for HTTP methods that can
 :  contain a body in the request (i.e. POST and PUT). It is an error, if this
 :  param is not the empty sequence for methods other then DELETE, GET, HEAD
 :  and OPTIONS.
 : @return a sequence of items, where the first item is a element of type
 :  http:responseType. The response element is also described in the
 :  specification.
 :  If there is one (or several, in case of multipart) response body, the response bodies
 :  are the next items in the sequence.
 :)
declare function http:read(
  $request as element(https:request)?,
  $href as xs:string?,
  $bodies as item()*) as item()+ {
  if (http:check-params($request, $href, $bodies))
  then
    let $req := if ($request) then validate { http:set-content-type($request) } else ()
    let $result := httpclientimpl:http-read-impl($req, $href, $bodies)
    return (validate {$result[1]}, fn:subsequence($result, 2))
  else ()
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the read function as follows:
 :
 :
 : http:read($request, $href, ())
 :
 :
 : @see documentation of read
 :      with three parameters.
 :
 : @param $request see parameter $request of read with three parameters
 : @param $href see parameter $href of read with three parameters
 : @return see return of read with three parameters
 :)
declare function http:read(
  $request as element(https:request)?,
  $href as xs:string?) as item()+ {
  http:read($request, $href, ())
};

(:~
 : Function for convenience.
 :
 : The result of this function is equal to calling the read function
 : as follows:
 :
 :
 : http:read((), $href, ())
 :
 :
 : @see documentation of read with three parameters.
 :
 : @param $href see parameter $href of read with three parameters
 : @return see return of read with three parameters
 :)
declare function http:read(
  $href as xs:string) as item()+ {
  http:read((), $href, ())
};

(:~
 : Helper function.
 :
 : This function takes an https:body element, copies it, and
 : adds a method attribute to the copy if there is none
 : in the original element.
 :
 : @param $body is the original https:body element
 : @return a https:body element with a corresponding @method
 :   attribute
 :)
declare function http:create-body (
  $body as element(https:body))
    as element(https:body) {
  <https:body>{$body/@*}
  {
    if ($body/@method) then
      ()
    else
      attribute method {
        if ($body/@media-type eq "text/xml" or
            $body/@media-type eq "application/xml" or
            $body/@media-type eq "text/xml-external-parsed-entity" or
            $body/@media-type eq "application/xml-external-parsed-entity") then
              "xml"
         else if ($body/@media-type eq "text/html") then "html"
         else if (fn:starts-with($body/@media-type/data(.), "text/")) then "text"
         else "binary"
      }
  }
  {$body/node()}
  </https:body>
};

(:~
 : Helper function.
 :
 : This function takes an https:multipart element, copies it and
 : adds a @method attribute to all body elements which don't have
 : one.
 :
 : @param $multipart the original https:multipart
 : @return a copy of $multipart with all $multipart/body/@method set
 :)
declare function http:create-multipart (
  $multipart as element(https:multipart))
    as element(https:multipart) {
  validate {
    <https:multipart>{$multipart/@*}
    {
    for $x in $multipart/node()
    return
      typeswitch($x)
        case element(https:body) return http:create-body($x)
        default return $x
    }
    </https:multipart>
  }
};

(:~
 : Helper function.
 :
 : This adds a default method attribute to all body elements which
 : don't contain a method attribute.
 :
 : @param $request The request which need to be copied.
 : @return A copy of $request with all request//body/@method set.
 :)
declare function http:set-content-type(
  $request as element(https:request)?)
    as element(https:request)? {
  if ($request) then
    validate
    {
      <http:request>{$request/@*}
      {
      for $x in $request/node()
      return
        typeswitch($x)
          case element(https:body) return http:create-body($x)
          case element(https:multipart) return http:create-multipart($x)
          default return $x
      }
      </http:request>
    }
  else ()
};

(:~
 : Private helper function used internally by this module.
 :
 : This function checks if the request, href, and bodies parameters
 : are consistent.
 :
 : @param $request The request which needs to be checked.
 : @param $href The href which needs to be checked.
 : @param $bodies The bodies element which needs to be checked.
 : @return true if the parameters are consistent. Otherwise,
 :         this function raises an error.
 :)
declare function http:check-params(
  $request as element(https:request)?,
  $href as xs:string?,
  $bodies as item()*) as xs:boolean {
  if (fn:empty($href) and fn:empty($request)) then
    fn:error($err:HCV01, "Not all required arguments are set.")
  else if ($href eq "") then
    fn:error($err:HCV01,
      "The href value is set to the empty string")
  else if (not(count($request//body[not(exists(node()))]) eq count($bodies))) then
    fn:error($err:HCV01,
      "The number of bodies without children is not equal the size of the bodies sequence")
  else
    fn:true()
};


Fix the db:attributes#3 BaseX function signature.

xquery version "3.1";
(:~
 : BaseX Database Module functions
 :
 : @see http://docs.basex.org/wiki/Database_Module
 :)
module namespace db = "http://basex.org/modules/db";

declare namespace a = "http://reecedunn.co.uk/xquery/annotations";
declare namespace o = "http://reecedunn.co.uk/xquery/options";

declare option o:requires "basex/7.0"; (: NOTE: 7.0 is the earliest version definitions are available for. :)

declare %a:since("basex", "7.0") function db:system() as element(system) external;
declare %a:since("basex", "9.0") function db:option($name as xs:string) as xs:string external;
declare %a:since("basex", "7.0") function db:info($db as xs:string) as element(database) external;
declare %a:since("basex", "8.6") function db:property($db as xs:string, $name as xs:string) as xs:anyAtomicType external;
declare %a:since("basex", "7.0") function db:list() as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string) as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string, $path as xs:string) as xs:string* external;
declare %a:since("basex", "7.1") function db:list-details() as element(database)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string) as element(resource)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string, $path as xs:string) as element(resource)* external;
declare %a:since("basex", "9.2") function db:dir($db as xs:string, $path as xs:string) as element()* external;
declare %a:since("basex", "7.0") function db:backups() as element(backup)* external;
declare %a:since("basex", "7.0") function db:backups($db as xs:string) as element(backup)* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string) as document-node()* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string, $path as xs:string) as document-node()* external;
declare %a:since("basex", "7.0") function db:open-pre($db as xs:string, $pre as xs:integer) as node() external;
declare %a:since("basex", "7.0") function db:open-id($db as xs:string, $id as xs:integer) as node() external;
declare %a:since("basex", "7.0") function db:node-pre($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:node-id($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:text($db as xs:string, $strings as xs:string*) as text()* external;
declare %a:since("basex", "7.2.1") function db:text-range($db as xs:string, $min as xs:string, $max as xs:string) as text()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:string*) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:string*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.2.1") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string, $name as xs:string) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.5") function db:create($db as xs:string) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.5") function db:drop($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:add($db as xs:string, $input as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:delete($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:copy($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:alter($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:create-backup($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:drop-backup($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:restore($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:rename($db as xs:string, $source as xs:string, $target as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item(), $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:store($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:since("basex", "7.3") function db:flush($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:name($node as node()) as xs:string external;
declare %a:since("basex", "7.7") function db:path($node as node()) as xs:string external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-raw($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-xml($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.1") function db:content-type($db as xs:string, $path as xs:string) as xs:string external;
declare %a:since("basex", "7.2.1") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:output") function db:output() external;
declare %a:since("basex", "8.2") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:cache") function db:output-cache() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string, $params as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "8.2") function db:event($name as xs:string, $query as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "7.8") function db:fulltext($db as item(), $terms as xs:string) as text()* external;

xquery version "3.1";
(:~
 : BaseX Database Module functions
 :
 : @see http://docs.basex.org/wiki/Database_Module
 :)
module namespace db = "http://basex.org/modules/db";

declare namespace a = "http://reecedunn.co.uk/xquery/annotations";
declare namespace o = "http://reecedunn.co.uk/xquery/options";

declare option o:requires "basex/7.0"; (: NOTE: 7.0 is the earliest version definitions are available for. :)

declare %a:since("basex", "7.0") function db:system() as element(system) external;
declare %a:since("basex", "9.0") function db:option($name as xs:string) as xs:string external;
declare %a:since("basex", "7.0") function db:info($db as xs:string) as element(database) external;
declare %a:since("basex", "8.6") function db:property($db as xs:string, $name as xs:string) as xs:anyAtomicType external;
declare %a:since("basex", "7.0") function db:list() as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string) as xs:string* external;
declare %a:since("basex", "7.0") function db:list($db as xs:string, $path as xs:string) as xs:string* external;
declare %a:since("basex", "7.1") function db:list-details() as element(database)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string) as element(resource)* external;
declare %a:since("basex", "7.1") function db:list-details($db as xs:string, $path as xs:string) as element(resource)* external;
declare %a:since("basex", "9.2") function db:dir($db as xs:string, $path as xs:string) as element()* external;
declare %a:since("basex", "7.0") function db:backups() as element(backup)* external;
declare %a:since("basex", "7.0") function db:backups($db as xs:string) as element(backup)* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string) as document-node()* external;
declare %a:since("basex", "7.0") function db:open($db as xs:string, $path as xs:string) as document-node()* external;
declare %a:since("basex", "7.0") function db:open-pre($db as xs:string, $pre as xs:integer) as node() external;
declare %a:since("basex", "7.0") function db:open-id($db as xs:string, $id as xs:integer) as node() external;
declare %a:since("basex", "7.0") function db:node-pre($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:node-id($nodes as node()*) as xs:integer* external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:retrieve($db as xs:string, $path as xs:string) as xs:base64Binary external;
declare %a:since("basex", "7.0") function db:text($db as xs:string, $strings as xs:string*) as text()* external;
declare %a:since("basex", "7.2.1") function db:text-range($db as xs:string, $min as xs:string, $max as xs:string) as text()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:string*) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute($db as xs:string, $strings as xs:strings*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.2.1") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string) as attribute()* external;
declare %a:since("basex", "7.0") function db:attribute-range($db as xs:string, $min as xs:string, $max as xs:string, $name as xs:string) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*) as attribute()* external;
declare %a:since("basex", "8.4") function db:token($db as xs:string, $tokens as xs:string*, $name as xs:string) as attribute()* external;
declare %a:since("basex", "7.5") function db:create($db as xs:string) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:since("basex", "7.5") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*) as empty-sequence() external;
declare %a:restrict-until("$inputs", "basex", "7.6", "item()")
        %a:restrict-until("$paths", "basex", "7.6", "xs:string")
        %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:create($db as xs:string, $inputs as item()*, $paths as xs:string*, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.5") function db:drop($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:add($db as xs:string, $input as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:add($db as xs:string, $input as item(), $path as xs:string, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:delete($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:copy($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:alter($db as xs:string, $name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:create-backup($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:drop-backup($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.8.2") function db:restore($name as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:optimize($db as xs:string, $all as xs:boolean, $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:rename($db as xs:string, $source as xs:string, $target as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:restrict-until("$options", "basex", "8.2.1", "item()")
        %a:restrict-since("$options", "basex", "8.2.1", "map(xs:string, xs:string)")
        %a:restrict-since("$options", "basex", "8.2.3", "map(*)")
        %a:restrict-since("$options", "basex", "8.6.7", "map(*)?")
        %a:since("basex", "7.0") function db:replace($db as xs:string, $path as xs:string, $input as item(), $options as item()?) as empty-sequence() external;
declare %a:since("basex", "7.0") function db:store($db as xs:string, $path as xs:string, $input as item()) as empty-sequence() external;
declare %a:since("basex", "7.3") function db:flush($db as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:name($node as node()) as xs:string external;
declare %a:since("basex", "7.7") function db:path($node as node()) as xs:string external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:exists($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-raw($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.0") function db:is-xml($db as xs:string, $path as xs:string) as xs:boolean external;
declare %a:since("basex", "7.1") function db:content-type($db as xs:string, $path as xs:string) as xs:string external;
declare %a:since("basex", "7.2.1") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:output") function db:output() external;
declare %a:since("basex", "8.2") %a:until("basex", "9.0") %a:see-also("basex", "9.0", "update:cache") function db:output-cache() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string) as empty-sequence() external;
declare %a:since("basex", "7.7") function db:export($db as xs:string, $path as xs:string, $params as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "8.2") function db:event($name as xs:string, $query as item()) as empty-sequence() external;
declare %a:since("basex", "7.0") %a:until("basex", "7.8") function db:fulltext($db as item(), $terms as xs:string) as text()* external;


Update json.xq

Update json.xq

Add a function for simplifying annotating existing XML with json:literal="true" before converting to JSON.

(:~
 :    Transform XML fragments into JSON. The target of this module
 :    is to create a straight-forward Javasript representation of data-centric XML. It does not try to handle
 :    mixed content nodes (with a mix of elements and text).
 :
 :
Special rules

 :
The root element will be absorbed, i.e. <root>text</root> becomes "text".

 :
Child elements with the same name are added to an array.

 :
If an element has attribute and text content, the text content becomes a
 :       property, e.g. '#text': 'my text'.

 :
In mixed content nodes, text nodes will be dropped.

 :
An empty element becomes 'null', i.e. <e/> becomes {"e": null}.

 :
An element with a single text child becomes a property with the value of the text child, i.e.
 :       <e>text</e> becomes {"e": "text"}

 :
If the attribute json:literal="true" is present on an element, then its text value
 :         is considered literal and not quoted as a string. Useful for boolean and numberic
 :         values! The json:annotate-json-literals function can be used to assist in this.

 :)
module namespace json="http://www.json.org";

(:~
: Helper function that annotates
: elements with `json:literal="true"`
: if their QNames are present in $literals
:
: @param $src One or more nodes to consider for annotation
: @param $literals The QNames of the elements to annotate
:
: @return The $src annotated with json:literal="true" as requested
:)
declare function json:annotate-json-literals($src as node()*, $literals as xs:QName+) as node()* {
    for $n in $src
    return
      typeswitch($n)
          case $d as document-node()
          return
            document {
              json:annotate-json-literals($d/*, $literals)
            }

          case $e as element()
          return
            element { node-name($e) } {
              if(node-name($e) = $literals)then
                attribute json:literal { "true" }
              else(),
              $e/@*,
              json:annotate-json-literals($e/node(), $literals)
            }

        default
        return
          $n
};

(:~
 :   Helper function: output element content for elements with more than one child node or attribute.
 :
 :   Special cases:
 :
 :
Child elements with the same name are added to an array.

 :
If an element has attribute and text content, the text content becomes a
 :       property, e.g. '#text': 'my text'.

 :
In mixed content nodes, text nodes will be dropped.

 :)
declare function json:element-helper($attribs as attribute()*, $children as node()*) {
    string-join((
        (: Output the attributes :)
        for $attr in $attribs
        return
            json:node-to-json($attr),
        if ($children instance of text()+) then
            for $text in $children
            return
                if($text/parent::node()/@json:literal)then
                (
                    $text
                )else(
                    concat('"#text": "', $text, '"')
                )
        else
            for $name in distinct-values(for $c in $children return node-name($c))
            return
                json:node-to-json($children[node-name(.) = $name])
    ),
    ', ')
};

(:~
 :   Helper function: output the contents of a node or attribute.
 :
 :   Special cases:
 :
 :
An empty element becomes 'null', i.e. <e/> becomes {"e": null}.

 :
An element with a single text child becomes a property with the value of the text child, i.e.
 :       <e>text</e> becomes {"e": "text"}

 :)
declare function json:contents-to-json($node as node()) {
    typeswitch ($node)
        case $elem as element() return
            let $children := $elem/node()
            let $attribs := $elem/@*
            return
                (: XML: <e/> JSON: "e": null :)
                if (count($children) eq 0 and count($attribs) eq 0) then
                    'null'
                (: XML: <e>text</e> JSON: "e": "text" :)
                else if (count($children) eq 1 and (count($attribs) eq 0 or $attribs[name() eq "json:literal"])
                    and $children[1] instance of text()) then
                    json:node-to-json($children[1])
                else
                    concat('{', json:element-helper($attribs, $children), '}')
        case $attr as attribute() return
            concat('"', string($attr), '"')
        case $text as text() return
            if($text/parent::node()/@json:literal)then(
                $text
            ) else (
                concat('"', $text, '"')
            )
        default return ()
};
(:~
 :    Helper function: convert a node into JSON.
 :)
declare function json:node-to-json($node as node()+) {
    typeswitch ($node)
        case $elem as element() return
            concat('"', node-name($elem), '" : ', json:contents-to-json($node))
        (: sequence of nodes passed from json:element-helper(), treat as array :)
        case $elements as element()+ return
            concat(
                '"', node-name($elements[1]), '" : [ ',
                string-join(
                    for $e in $elements return json:contents-to-json($e),
                ', '),
                ']'
            )
        case $attr as attribute() return
            if(name($attr) ne "json:literal")then(
                concat('"@', node-name($attr), '": ', json:contents-to-json($attr))
            )else()
        default return
            json:contents-to-json($node)
};

(:~
 :    Main entry point of the module. Convert a single node into JSON.
 :    The root element will be absorbed.
 :)
declare function json:xml-to-json($node as node()) {
    json:contents-to-json($node)
};

(:~
 :    Transform XML fragments into JSON. The target of this module
 :    is to create a straight-forward Javasript representation of data-centric XML. It does not try to handle
 :    mixed content nodes (with a mix of elements and text).
 :
 :
Special rules

 :
The root element will be absorbed, i.e. <root>text</root> becomes "text".

 :
Child elements with the same name are added to an array.

 :
If an element has attribute and text content, the text content becomes a
 :       property, e.g. '#text': 'my text'.

 :
In mixed content nodes, text nodes will be dropped.

 :
An empty element becomes 'null', i.e. <e/> becomes {"e": null}.

 :
An element with a single text child becomes a property with the value of the text child, i.e.
 :       <e>text</e> becomes {"e": "text"}

 :
If the attribute json:literal="true" is present on an element, then its text value is considered literal and not quoted as a string. Useful for boolean and numberic values!

 :)
module namespace json="http://www.json.org";

(:~
 :   Helper function: output element content for elements with more than one child node or attribute.
 :
 :   Special cases:
 :
 :
Child elements with the same name are added to an array.

 :
If an element has attribute and text content, the text content becomes a
 :       property, e.g. '#text': 'my text'.

 :
In mixed content nodes, text nodes will be dropped.

 :)
declare function json:element-helper($attribs as attribute()*, $children as node()*) {
    string-join((
        (: Output the attributes :)
        for $attr in $attribs
        return
            json:node-to-json($attr),
        if ($children instance of text()+) then
            for $text in $children
            return
                if($text/parent::node()/@json:literal)then
                (
                    $text
                )else(
                    concat('"#text": "', $text, '"')
                )
        else
            for $name in distinct-values(for $c in $children return node-name($c))
            return
                json:node-to-json($children[node-name(.) = $name])
    ),
    ', ')
};

(:~
 :   Helper function: output the contents of a node or attribute.
 :
 :   Special cases:
 :
 :
An empty element becomes 'null', i.e. <e/> becomes {"e": null}.

 :
An element with a single text child becomes a property with the value of the text child, i.e.
 :       <e>text</e> becomes {"e": "text"}

 :)
declare function json:contents-to-json($node as node()) {
    typeswitch ($node)
        case $elem as element() return
            let $children := $elem/node()
            let $attribs := $elem/@*
            return
                (: XML: <e/> JSON: "e": null :)
                if (count($children) eq 0 and count($attribs) eq 0) then
                    'null'
                (: XML: <e>text</e> JSON: "e": "text" :)
                else if (count($children) eq 1 and (count($attribs) eq 0 or $attribs[name() eq "json:literal"])
                    and $children[1] instance of text()) then
                    json:node-to-json($children[1])
                else
                    concat('{', json:element-helper($attribs, $children), '}')
        case $attr as attribute() return
            concat('"', string($attr), '"')
        case $text as text() return
            if($text/parent::node()/@json:literal)then(
                $text
            ) else (
                concat('"', $text, '"')
            )
        default return ()
};
(:~
 :    Helper function: convert a node into JSON.
 :)
declare function json:node-to-json($node as node()+) {
    typeswitch ($node)
        case $elem as element() return
            concat('"', node-name($elem), '" : ', json:contents-to-json($node))
        (: sequence of nodes passed from json:element-helper(), treat as array :)
        case $elements as element()+ return
            concat(
                '"', node-name($elements[1]), '" : [ ',
                string-join(
                    for $e in $elements return json:contents-to-json($e),
                ', '),
                ']'
            )
        case $attr as attribute() return
            if(name($attr) ne "json:literal")then(
                concat('"@', node-name($attr), '": ', json:contents-to-json($attr))
            )else()
        default return
            json:contents-to-json($node)
};

(:~
 :    Main entry point of the module. Convert a single node into JSON.
 :    The root element will be absorbed.
 :)
declare function json:xml-to-json($node as node()) {
    json:contents-to-json($node)
};