updated namespace prefix in the jsoniq module to jn

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

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

declare namespace jdm = "http://www.jsoniq.org/";

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

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

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

(:~
 : This function has the same semantics as fn:parse-xml(), except that
 : it parses the string as JSON (not XML), and returns an Object or
 : Array rather than an XML document.
 :
 : @param $j A string containing a valid JSON text.
 : @return a JSON Object or Array item.
 :)
declare function jn:parse-json($j as xs:string) as json-item()? external;

(:~
 : Returns the names used in the Pairs of the object. This function is
 : equivalent to
 :
 :    for $p in jn:pairs($arg) return jn:name($p)
 :
 : The names will be returned in an implementation-defined order
 :
 : @param $o A JSON Object.
 : @return The names of pairs in the object.
 :)
declare function jn:names($o as object()) as xs:string* external;

(:~
 : Returns the name of the Pair.
 :
 : @param $p A JSON Pair.
 : @return The name of the Pair.
 :)
declare function jn:name($p as pair()) as xs:string external;

(:~
 : Returns the Pairs of the Object. The pairs will be returned in an
 : implementation-defined order.
 :
 : @param $o A JSON Object.
 : @return A sequence of JSON Pair items.
 :)
declare function jn:pairs($o as object()) as pair()* external;

(:~
 : Returns the Pair of an Object with the specified name. If no such
 : Pair exists in the Object, returns the empty sequence.
 :
 : @param $o A JSON Object.
 : @param $n A name.
 : @return The Pair with the given name, or empty sequence.
 :)
declare function jn:pair($o as object(), $n as xs:string) as pair()? external;

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

(:~
 : Returns the size of a JSON Object or JSON Array. The size of an Object
 : is the number of Pairs contained within it; the size of an Array is
 : the number of members contained within it.
 :
 : @param $j A JSON Object or JSON Array.
 : @return The number of items in $j.
 : @error jn:JUDY0060 if $j is a JSON Pair.
 :)
declare function jn:size($j as json-item()) as xs:integer external;

(:~
 : Returns all Pairs in an Object, or all members of an Array. When
 : passed an Object, the Pairs will be returned in an implementation-
 : defined order.
 :
 : @param $j A JSON Object or JSON Array.
 : @return All Pairs/members of $j.
 : @error jn:JUDY0060 if $j is a JSON Pair.
 :)
declare function jn:values($j as json-item()) as item()* external;

(:~
 : Returns the value of a JSON Pair.
 :
 : @param $p A JSON Pair.
 : @return the value of $p.
 :)
declare function jn:value($p as pair()) as item() external;

(:~
 : Returns the jdm:null value null.
 :
 : @return the said value
 :)
declare function jn:null() as jdm:null external;

(:~
 : Insert one or more pairs into an object. Recall that a JSON Object
 : may not contain two pairs with the same name. This function will not
 : replace a pair in an object.
 :
 : @param $o A JSON Object.
 : @param $p A sequence of Pairs to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the pairs into the object.
 : @error jn:JUDY0060 if pair with the given name already exists.
 :)
declare updating function jn:insert-into(
  $o as object(),
  $p as pair()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : at the beginning of the array.
 :
 : @param $a A JSON Array.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 :)
declare updating function jn:insert-as-first(
  $a as array(),
  $i as item()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : after the specified position in the array.
 :
 : The position must exist in the array. You cannot specify an position of 0
 : to insert at the beginning of the array (use jn:insert-as-first($a, ...) or
 : jn:insert-before($a, 1, ...)).
 :
 : @param $a A JSON Array.
 : @param $pos The position.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 : @error jn:JUDY0061 if the position doesn't select an existing array member
 :)
declare updating function jn:insert-after(
  $a as array(),
  $pos as xs:integer,
  $i as item()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : before the specified position in the array.
 :
 : The position must exist in the array.
 :
 : @param $a A JSON Array.
 : @param $pos The position.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 : @error jn:JUDY0061 if the position doesn't select an existing array member
 :)
declare updating function jn:insert-before(
  $a as array(),
  $pos as xs:integer,
  $i as item()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : at the end of the array.
 :
 : @param $a A JSON Array.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 :)
declare updating function jn:insert-as-last(
  $a as array(),
  $i as item()*) external;

(:~
 : Delete an item from a JSON Array or a Pair from a JSON Object.
 :
 : If $j is an Object and $selector is an xs:string, deletes the Pair
 : $i($selector) if it exists, raising an error if it does not exist.
 :
 : If $j is an Array and $selector is an xs:integer, deletes the member
 : $i($selector) if it exists, raising an error if it does not exist.
 :
 : In any other case, a type error is raised.
 : @param $j A JSON Array or JSON Object.
 : @param $select An xs:string (if $j is an Object) or xs:integer
 :   (if $j is an array).
 : @return An empty XDM instance and a pending update list which, once
 :   applied, deletes the item from the array or object.
 : @error jn:JUDY0061 if the selector doesn't select an existing pair or
 :   array member
 : @error jn:JUDY0062 if the first argument is a pair
 : @error jn:JUDY0063 invalid type for second argument (must be xs:integer
 :   if first argument is an array or xs:string if first argument is an object)
 :)
declare updating function jn:delete(
  $j as json-item(),
  $selector as xs:anyAtomicType)
{
  try {
    typeswitch ($j)
    case $o as object()
      return jn:delete-pair($o, $selector treat as xs:string)
    case $a as array()
      return jn:delete-member($a, $selector treat as xs:integer)
    default return
      fn:error(
        fn:QName("http://www.jsoniq.org/errors", "JUDY0062"),
        "first argument to delete function is pair() but must be array() or object()",
        $j)
   } catch err:XPDY0050 {
     fn:error(
       fn:QName("http://www.jsoniq.org/errors", "JUDY0063"),
       concat(
         schema:schema-type($selector),
         ": invalid type for second argument; should be ",
         typeswitch ($j)
         case object() return "xs:string"
         default return "xs:integer"
       ),
       $selector
     )
   }
};

(:~
 : Delete a pair from a JSON Object by name.
 :
 : @param $o A JSON Object.
 : @param $n The name of the Pair to delete.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, deletes the pair from the object.
 : @error jn:JUDY0061 if the key doesn't select an existing pair.
 :)
declare updating function jn:delete-pair(
  $o as object(),
  $key as xs:string) external;

(:~
 : Delete an item from a JSON Array.
 :
 : @param $a A JSON Array.
 : @param $pos The position in the array to delete.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, deletes the item from the array.
 : @error jn:JUDY0061 if the position doesn't select an existing member
 :)
declare updating function jn:delete-member(
  $a as array(),
  $pos as xs:integer) external;

(:~
 : Assigns a new name to a JSON Pair in an Object.
 :
 : @param $o A JSON Object.
 : @param $old-name The current name of a Pair in the Object.
 : @param $new-name The new name for the Pair.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, renames the pair.
 : @error jn:JUDY0061 if $old-name doesn't select an existing pair.
 :)
declare updating function jn:rename(
  $o as object(),
  $old-name as xs:string,
  $new-name as xs:string) external;

(:~
 : Replace an item in an Array, or the value of a Pair in an Object.
 :
 : If $j is an Object and $selector is an xs:string, replaces the value
 : of the Pair $i($selector) if it exists, raising an error if it does
 : not exist.
 :
 : If $j is an Array and $selector is an xs:integer, replaces the member
 : $i($selector) if it exists, raising an error if it does not exist.
 :
 : In any other case, a type error is raised.
 :
 : @param $j A JSON Object or Array.
 : @param $select An xs:string (if $j is an Object) or xs:integer
 :   (if $j is an array).
 : @param $new-val The new item to insert into the Object or Array in
 :   place of the old value.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, replaces the selected item in the object or array.
 : @error jn:JUDY0061 if $selector is wrong. (QQQ needs testing)
 :)
declare updating function jn:replace-value(
  $j as json-item(),
  $selector as xs:anyAtomicType,
  $new-val as item())
{
  try {
    typeswitch ($j)
    case $o as object()
      return jn:replace-value-in-object($o, $selector treat as xs:string, $new-val)
    case $a as array()
      return jn:replace-value-in-array($a, $selector treat as xs:integer, $new-val)
    default return
      fn:error(
        fn:QName("http://www.jsoniq.org/errors", "JUDY0062"),
        "first argument to replace-value function is pair() but must be array() or object()",
        $j)
   } catch err:XPDY0050 {
     fn:error(
       fn:QName("http://www.jsoniq.org/errors", "JUDY0063"),
       concat(
         schema:schema-type($selector),
         ": invalid type for second argument; should be ",
         typeswitch ($j)
         case object() return "xs:string"
         default return "xs:integer"
       ),
       $selector
     )
   }
};

(:~
 : Replace the value of a Pair in an Object.
 :
 : @param $o A JSON Object.
 : @param $n The name of a Pair in $o.
 : @param $new-val The new value for the Pair.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, replaces the value of the selected pair in the object.
 : @error jn:JUDY0061 if the position doesn't select an existing member
 :)
declare updating function jn:replace-value-in-object(
  $o as object(),
  $n as xs:string,
  $new-val as item()) external;

(:~
 : Replace an item in a JSON Array.
 : @param $a A JSON Array.
 : @param $pos The position in the array to replace.
 : @param $new-valu The new item to put in the array in place of the
 : existing item.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, replaces the selected item in the array.
 : @error jn:JUDY0061 if the position doesn't select an existing member
 :)
declare updating function jn:replace-value-in-array(
  $a as array(),
  $pos as xs:integer,
  $new-val as item()) external;

(:~
 : This module provides the functions defined by the JSONiq specification,
 : sections 1.7 (Functions) and 1.10 (Update Primitives). JSONiq extends
 : the XQuery specification to also deal with JSON data natively. See
 :
 :     http://www.jsoniq.org/
 :
 : for details.
 :
 : This module depends on having the JSONiq feature enabled in Zorba,
 : ie, Zorba must be compiled with ZORBA_WITH_JSON.
 :)
module namespace j = "http://www.jsoniq.org/functions";

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

declare namespace jdm = "http://www.jsoniq.org/";

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

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

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

(:~
 : This function has the same semantics as fn:parse-xml(), except that
 : it parses the string as JSON (not XML), and returns an Object or
 : Array rather than an XML document.
 :
 : @param $j A string containing a valid JSON text.
 : @return a JSON Object or Array item.
 :)
declare function j:parse-json($j as xs:string) as json-item()? external;

(:~
 : Returns the names used in the Pairs of the object. This function is
 : equivalent to
 :
 :    for $p in j:pairs($arg) return j:name($p)
 :
 : The names will be returned in an implementation-defined order
 :
 : @param $o A JSON Object.
 : @return The names of pairs in the object.
 :)
declare function j:names($o as object()) as xs:string* external;

(:~
 : Returns the name of the Pair.
 :
 : @param $p A JSON Pair.
 : @return The name of the Pair.
 :)
declare function j:name($p as pair()) as xs:string external;

(:~
 : Returns the Pairs of the Object. The pairs will be returned in an
 : implementation-defined order.
 :
 : @param $o A JSON Object.
 : @return A sequence of JSON Pair items.
 :)
declare function j:pairs($o as object()) as pair()* external;

(:~
 : Returns the Pair of an Object with the specified name. If no such
 : Pair exists in the Object, returns the empty sequence.
 :
 : @param $o A JSON Object.
 : @param $n A name.
 : @return The Pair with the given name, or empty sequence.
 :)
declare function j:pair($o as object(), $n as xs:string) as pair()? external;

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

(:~
 : Returns the size of a JSON Object or JSON Array. The size of an Object
 : is the number of Pairs contained within it; the size of an Array is
 : the number of members contained within it.
 :
 : @param $j A JSON Object or JSON Array.
 : @return The number of items in $j.
 : @error j:JUDY0060 if $j is a JSON Pair.
 :)
declare function j:size($j as json-item()) as xs:integer external;

(:~
 : Returns all Pairs in an Object, or all members of an Array. When
 : passed an Object, the Pairs will be returned in an implementation-
 : defined order.
 :
 : @param $j A JSON Object or JSON Array.
 : @return All Pairs/members of $j.
 : @error j:JUDY0060 if $j is a JSON Pair.
 :)
declare function j:values($j as json-item()) as item()* external;

(:~
 : Returns the value of a JSON Pair.
 :
 : @param $p A JSON Pair.
 : @return the value of $p.
 :)
declare function j:value($p as pair()) as item() external;

(:~
 : Returns the jdm:null value null.
 :
 : @return the said value
 :)
declare function j:null() as jdm:null external;

(:~
 : Insert one or more pairs into an object. Recall that a JSON Object
 : may not contain two pairs with the same name. This function will not
 : replace a pair in an object.
 :
 : @param $o A JSON Object.
 : @param $p A sequence of Pairs to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the pairs into the object.
 : @error j:JUDY0060 if pair with the given name already exists.
 :)
declare updating function j:insert-into(
  $o as object(),
  $p as pair()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : at the beginning of the array.
 :
 : @param $a A JSON Array.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 :)
declare updating function j:insert-as-first(
  $a as array(),
  $i as item()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : after the specified position in the array.
 :
 : The position must exist in the array. You cannot specify an position of 0
 : to insert at the beginning of the array (use j:insert-as-first($a, ...) or
 : j:insert-before($a, 1, ...)).
 :
 : @param $a A JSON Array.
 : @param $pos The position.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 : @error j:JUDY0061 if the position doesn't select an existing array member
 :)
declare updating function j:insert-after(
  $a as array(),
  $pos as xs:integer,
  $i as item()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : before the specified position in the array.
 :
 : The position must exist in the array.
 :
 : @param $a A JSON Array.
 : @param $pos The position.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 : @error j:JUDY0061 if the position doesn't select an existing array member
 :)
declare updating function j:insert-before(
  $a as array(),
  $pos as xs:integer,
  $i as item()*) external;

(:~
 : Insert one or more items into a JSON Array. The items will be inserted
 : at the end of the array.
 :
 : @param $a A JSON Array.
 : @param $i A sequence of items to insert.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, inserts the items into the array.
 :)
declare updating function j:insert-as-last(
  $a as array(),
  $i as item()*) external;

(:~
 : Delete an item from a JSON Array or a Pair from a JSON Object.
 :
 : If $j is an Object and $selector is an xs:string, deletes the Pair
 : $i($selector) if it exists, raising an error if it does not exist.
 :
 : If $j is an Array and $selector is an xs:integer, deletes the member
 : $i($selector) if it exists, raising an error if it does not exist.
 :
 : In any other case, a type error is raised.
 : @param $j A JSON Array or JSON Object.
 : @param $select An xs:string (if $j is an Object) or xs:integer
 :   (if $j is an array).
 : @return An empty XDM instance and a pending update list which, once
 :   applied, deletes the item from the array or object.
 : @error j:JUDY0061 if the selector doesn't select an existing pair or
 :   array member
 : @error j:JUDY0062 if the first argument is a pair
 : @error j:JUDY0063 invalid type for second argument (must be xs:integer
 :   if first argument is an array or xs:string if first argument is an object)
 :)
declare updating function j:delete(
  $j as json-item(),
  $selector as xs:anyAtomicType)
{
  try {
    typeswitch ($j)
    case $o as object()
      return j:delete-pair($o, $selector treat as xs:string)
    case $a as array()
      return j:delete-member($a, $selector treat as xs:integer)
    default return
      fn:error(
        fn:QName("http://www.jsoniq.org/errors", "JUDY0062"),
        "first argument to delete function is pair() but must be array() or object()",
        $j)
   } catch err:XPDY0050 {
     fn:error(
       fn:QName("http://www.jsoniq.org/errors", "JUDY0063"),
       concat(
         schema:schema-type($selector),
         ": invalid type for second argument; should be ",
         typeswitch ($j)
         case object() return "xs:string"
         default return "xs:integer"
       ),
       $selector
     )
   }
};

(:~
 : Delete a pair from a JSON Object by name.
 :
 : @param $o A JSON Object.
 : @param $n The name of the Pair to delete.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, deletes the pair from the object.
 : @error j:JUDY0061 if the key doesn't select an existing pair.
 :)
declare updating function j:delete-pair(
  $o as object(),
  $key as xs:string) external;

(:~
 : Delete an item from a JSON Array.
 :
 : @param $a A JSON Array.
 : @param $pos The position in the array to delete.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, deletes the item from the array.
 : @error j:JUDY0061 if the position doesn't select an existing member
 :)
declare updating function j:delete-member(
  $a as array(),
  $pos as xs:integer) external;

(:~
 : Assigns a new name to a JSON Pair in an Object.
 :
 : @param $o A JSON Object.
 : @param $old-name The current name of a Pair in the Object.
 : @param $new-name The new name for the Pair.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, renames the pair.
 : @error j:JUDY0061 if $old-name doesn't select an existing pair.
 :)
declare updating function j:rename(
  $o as object(),
  $old-name as xs:string,
  $new-name as xs:string) external;

(:~
 : Replace an item in an Array, or the value of a Pair in an Object.
 :
 : If $j is an Object and $selector is an xs:string, replaces the value
 : of the Pair $i($selector) if it exists, raising an error if it does
 : not exist.
 :
 : If $j is an Array and $selector is an xs:integer, replaces the member
 : $i($selector) if it exists, raising an error if it does not exist.
 :
 : In any other case, a type error is raised.
 :
 : @param $j A JSON Object or Array.
 : @param $select An xs:string (if $j is an Object) or xs:integer
 :   (if $j is an array).
 : @param $new-val The new item to insert into the Object or Array in
 :   place of the old value.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, replaces the selected item in the object or array.
 : @error j:JUDY0061 if $selector is wrong. (QQQ needs testing)
 :)
declare updating function j:replace-value(
  $j as json-item(),
  $selector as xs:anyAtomicType,
  $new-val as item())
{
  try {
    typeswitch ($j)
    case $o as object()
      return j:replace-value-in-object($o, $selector treat as xs:string, $new-val)
    case $a as array()
      return j:replace-value-in-array($a, $selector treat as xs:integer, $new-val)
    default return
      fn:error(
        fn:QName("http://www.jsoniq.org/errors", "JUDY0062"),
        "first argument to replace-value function is pair() but must be array() or object()",
        $j)
   } catch err:XPDY0050 {
     fn:error(
       fn:QName("http://www.jsoniq.org/errors", "JUDY0063"),
       concat(
         schema:schema-type($selector),
         ": invalid type for second argument; should be ",
         typeswitch ($j)
         case object() return "xs:string"
         default return "xs:integer"
       ),
       $selector
     )
   }
};

(:~
 : Replace the value of a Pair in an Object.
 :
 : @param $o A JSON Object.
 : @param $n The name of a Pair in $o.
 : @param $new-val The new value for the Pair.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, replaces the value of the selected pair in the object.
 : @error j:JUDY0061 if the position doesn't select an existing member
 :)
declare updating function j:replace-value-in-object(
  $o as object(),
  $n as xs:string,
  $new-val as item()) external;

(:~
 : Replace an item in a JSON Array.
 : @param $a A JSON Array.
 : @param $pos The position in the array to replace.
 : @param $new-valu The new item to put in the array in place of the
 : existing item.
 : @return An empty XDM instance and a pending update list which, once
 :   applied, replaces the selected item in the array.
 : @error j:JUDY0061 if the position doesn't select an existing member
 :)
declare updating function j:replace-value-in-array(
  $a as array(),
  $pos as xs:integer,
  $new-val as item()) external;


Module update.

Module update.

xquery version "3.0";

(:
 : Copyright 2006-2013 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 and refresh indexes which are
 : declared in the prolog of a module.
 :

 : This module is part of
 : Zorba's XQuery Data Definition Facility.
 : All the indexes managed by this module have to be pre-declared in the prolog
 : of a library module.
 : Please refer to the
 : general documentation
 : for more information and examples.
 :
 : @see Data Lifecycle
 : @see XQuery Data Definition Facility
 : @see http://zorba.io/modules/store/static/indexes/ddl
 : @see http://zorba.io/modules/store/static/collections/dml
 : @see http://zorba.io/modules/store/static/collections/ddl
 : @see http://zorba.io/modules/store/static/integrity-constraints/ddl
 : @see http://zorba.io/modules/store/static/integrity-constraints/dml
 : @see http://zorba.io/errors
 :
 : @author Zorba Team
 : @project Zorba/Data Store/Indexes/Static Data Manipulation
 :)
module namespace idml = "http://zorba.io/modules/store/static/indexes/dml";

declare namespace an = "http://zorba.io/annotations";
declare namespace zerr = "http://zorba.io/errors";

declare namespace ver = "http://zorba.io/options/versioning";
declare option ver:module-version "2.0";

(:===========================================================================:)

(:~
 : Gets the domain nodes from an index associated by value equality with a
 : given search tuple.
 :

 : The search tuple consists of a number of search keys where each
 : search key is either an atomic item or the empty sequence.  The number of
 : search keys given must be equal to the number of keys declared for the
 : index. Since the number of keys differs from one index to another, this
 : function is variadic.
 : @param $name The of the index to probe.
 : @param $key_i A search key used to probe the index with. The i-th search key
 : corresponds to the i-th key expression in the index declaration.
 : @return The set of domain nodes for which the following XQuery expression
 : returns true:
 :

 :    $key1 eq $node/keyExpr1 and ... and $keyM eq $node/keyExprM
 :

 : where keyExpri is the expression specified in the i-th
 : keyspec of the index.
 : @error zerr:ZDDY0021 if the index is not declared.
 : @error zerr:ZDDY0023 if the index does not exist.
 : @error zerr:ZDDY0025 if the number of search keys passed as arguments is not
 : the same as the number of keys declared for the index.
 : @error err:XPTY0004 if a non-empty seach key is given whose type does not
 : match the sequence type specified in the corresponding keyspec.
 :)
declare %an:variadic function
idml:probe-index-point-value( $name as xs:QName, $key_i as xs:anyAtomicType? )
  as node()* external;

(:~
 : This is an extension of the probe-index-point-value() function
 : in that it allows index items to be skipped.
 :
 : @param $name The name of the index to probe.
 : @param $skip The number of index items to skip.
 : @param $key_i The search keys used to probe the index with. The i-th search
 : key corresponds to the i-th key expression in the index declaration.
 : @return The set of domain nodes that satisfy the search condition.
 : @error zerr:ZDDY0021 if the index is not declared.
 : @error zerr:ZDDY0023 if the index does not exist.
 : @error zerr:ZDDY0025 if the number of search keys passed as arguments is not
 : the same as the number of keys declared for the index.
 : @error err:XPTY0004 if a non-empty seach key is given whose type does not
 : match the sequence type specified in the corresponding keyspec.
 :)
declare %an:variadic function
idml:probe-index-point-value-skip( $name as xs:QName,
                                   $skip as xs:integer,
                                   $key_i as xs:anyAtomicType? )
  as node()* external;

(:~
 : Gets from an index the domain nodes associated by general equality with a
 : given search sequence .
 : The search sequence consists of an arbitrary number of search keys
 : where each search key is an atomic item.
 : The function is supported by general indexes only.
 :
 : @param $name The name of the index to probe.
 : @param $key The search sequence.
 : @return The set of domain nodes for which the following XQuery expression
 : returns true:
 :

 :    $keys = $node/keyExpr
 :

 : where keyExpr is the expression specified in the keyspec of the index
 : (remember that for general indexes, there can be only one keyspec).
 : @error err:XPTY0004 if the search sequence contains a search key whose type
 : does not match the sequence type specified in the keyspec of the index.
 : @error zerr:ZDDY0021 if the index with name $name is not declared.
 : @error zerr:ZDDY0023 if the index with name $name does not exist.
 : @error zerr:ZDDY0029 if the index is not general.
 :)
declare function idml:probe-index-point-general( $name as xs:QName,
                                                 $key  as xs:anyAtomicType* )
  as node()* external;

(:~
 : Gets the domain nodes associated by value order-comparison (operators
 : le, lt, ge, gt) with a
 : given search box.
 :

 : The search box is specified as a number M of rangespecs
 : where each rangespec consists of six values.
 : The number M must be greater than 0 and less than or equal to the
 : number N of keyspecs found in the index declaration.
 : If M < N, then the "missing" rangespecs are assumed to have
 : the following value: [(), (), false, false, false, false].
 : As a result, we can assume that M = N.
 : Remember that for general indexes, there can be only one IndexKeySpec and,
 : as a result for general indexes, M = N = 1.
 : Since the number of keys differs from one index to another,
 : this function is variadic.
 :

 : The ith rangespec corresponds to the ith keyspec, and
 : specifies a search condition on the key values that are produced by
 : evaluating that keyspec for every domain node.
 : Specifically, we define the ith rangespec result as the
 : set of domain nodes for which the following XQuery expression returns
 : true:
 :

 :    if ( $haveLowerBound-i and $haveUpperBound-i ) then
 :      $lowerBound-i lop $node/keyExpr-i and $node/keyExpr-i uop $upperBound-i
 :    else if ( $haveLowerBound-i ) then
 :      $lowerBound-i lop $node/keyExpr-i
 :    else if ( $haveUpperBound-i ) then
 :      $node/keyExpr-i uop $upperBound-i
 :    else
 :      fn:true()
 :

 : where keyExpr-i is the expression specified by the ith
 : keyspec of the index, lop is either the le or the
 : lt operator depending on whether
 : $lowerBoundsIncluded-i is true or false, and uop is
 : either the le or the lt operator depending on whether
 : $upperBoundsIncluded-i is true or false.
 :
 : @param $name The name of the index to probe.
 : @param $lowerBound-i The lower bound in a range of key values.
 : @param $upperBound-i The upper bound in a range of key values.
 : @param $haveLowerBound-i 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 $lowerBound-i value.
 : @param $haveUpperBound-i 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 $upperBound-i value.
 : @param $lowerBoundIncluded-i If false, then the range is open from below,
 : i.e., the $lowerBound-i value is not considered part of the
 : range. Otherwise, the range is closed from below, i.e., the
 : $lowerBound-i value is part of the range.
 : @param $upperBoundIncluded-i If false, then the range is open from above,
 : i.e., the $upperBound-i value is not considered part of the
 : range. Otherwise, the range is closed from above, i.e., the
 : $upperBound-i value is part of the range.
 : @return The intersection of all the rangespec results.
 : @error zerr:ZDDY0021 if the index is not declared.
 : @error zerr:ZDDY0023 if the index does not exist.
 : @error zerr:ZDDY0025 if the number of rangespecs passed as arguments is zero
 : or greater than the number of keys declared for the index.
 : @error zerr:ZDDY0026 if the index is not a range index.
 : @error err:XPTY0004 if $haveLowerBound-i is true and
 : $lowerBound-i is an atomic item whose type does not match the
 : sequence type specified by the ith keyspec, or
 : $haveUpperBound-i is true and $upperBound-i is an
 : atomic item whose type does not match the sequence type specified by the
 : ith keyspec.
 : @error zerr:ZDDY0034 if (a) the index is general (in which case there is
 : only one rangespac), (b) the index is untyped, (c) there is both a lower and
 : an upper bound, and (d) if T1 and T2 are the types of the lower and upper
 : bound, neither T1 is a subtype of T2 nor T2 is a subtype of T1.
 :)
declare %an:variadic function
idml:probe-index-range-value( $name                 as xs:QName,
                              $lowerBound-i         as xs:anyAtomicType?,
                              $upperBound-i         as xs:anyAtomicType?,
                              $haveLowerBound-i     as xs:boolean,
                              $haveUpperBound-i     as xs:boolean,
                              $lowerBoundIncluded-i as xs:boolean,
                              $upperBoundIncluded-i as xs:boolean )
  as node()* external;

(:~
 : This function is an extension of the probe-index-range-value()
 : function that index items to be skipped.
 :
 : @param $name The QName of the index to probe
 : @param $skip The number of index items to skip.
 : @param $lowerBound-i The lower bound in a range of key values.
 : @param $upperBound-i The upper bound in a range of key values.
 : @param $haveLowerBound-i 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 $lowerBound-i value.
 : @param $haveUpperBound-i 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 $upperBound-i value.
 : @param $lowerBoundIncluded-i If false, then the range is open from below,
 : i.e., the lowerBound-i value is not considered part of the range. Otherwise,
 : the range is closed from below, i.e., the $lowerBound-i value
 : is part of the range.
 : @param $upperBoundIncluded-i If false, then the range is open from above,
 : i.e., the upperBound-i value is not considered part of the range. Otherwise,
 : the range is closed from above, i.e., the $upperBound-i value
 : is part of the range.
 : @return The set of domain nodes that satisfy the search condition.
 : @error zerr:ZDDY0021 if the index with name $name is not declared.
 : @error zerr:ZDDY0023 if the index with name $name does not exist.
 : @error zerr:ZDDY0025 if the number of rangespecs passed as arguments is zero
 : or greater than the number of keys declared for the index.
 : @error zerr:ZDDY0026 if the index is not a range index.
 : @error err:XPTY0004 if $haveLowerBound-i is true and
 : $lowerBound-i is an atomic item whose type does not match the
 : sequence type specified by the ith keyspec, or
 : $haveUpperBound-i is true and $upperBound-i is an
 : atomic item whose type does not match the sequence type specified by the
 : ith keyspec.
 : @error zerr:ZDDY0034 if (a) the index is general (in which case there is
 : only one rangespac), (b) the index is untyped, (c) there is both a lower and
 : an upper bound, and (d) if T1 and T2 are the types of the lower and upper
 : bound, neither T1 is a subtype of T2 nor T2 is a subtype of T1.
 :)
declare %an:variadic function
idml:probe-index-range-value-skip( $name                 as xs:QName,
                                   $skip                 as xs:integer,
                                   $lowerBound-i         as xs:anyAtomicType?,
                                   $upperBound-i         as xs:anyAtomicType?,
                                   $haveLowerBound-i     as xs:boolean,
                                   $haveUpperBound-i     as xs:boolean,
                                   $lowerBoundIncluded-i as xs:boolean,
                                   $upperBoundIncluded-i as xs:boolean )
  as node()* external;

(:~
 : Gets the domain nodes associated by general order-comparison (operators
 : <=, <, >=,
 : >) with one or two search sequences.
 :

 : Each search sequence consists of an arbitrary number of
 : search keys where each search key is an atomic item.
 : This method is supported by general range indexes only.
 : Its result is either an error or the set of domain nodes for which the
 : following XQuery expression returns true:
 :

 :    if ( $haveLowerBound and $haveUpperBound ) then
 :      $lowerBoundKeys lop $node/keyExpr and $node/keyExpr uop $upperBoundKeys
 :    else if ( $haveLowerBound ) then
 :      $lowerBoundKeys lop $node/keyExpr
 :    else if ( $haveUpperBound ) then
 :      $node/keyExpr uop $upperBoundKeys
 :    else
 :      fn:true()
 :

 : where keyExpr is the expression specified in the keyspec of the
 : index, lop is either the <= or the <
 : operator depending on whether $lowerBoundsIncluded is true or
 : false, and uop is either the <= or the
 : < operator depending on whether
 : $upperBoundsIncluded is true or false.
 :
 : @param $name The of the index to probe.
 : @param $lowerBound The lower bound search sequence.
 : @param $upperBound The upper bound search sequence.
 : @param $haveLowerBound Whether a lower bound search sequence exists or not.
 : @param $haveUpperBound Whether an upper bound search sequence exists or not.
 : @param $lowerBoundIncluded Whether to use the <= or the
 : < operator when comparing a search key from
 : $lowerBound with an index key.
 : @param $upperBoundIncluded Whether to use the <= or the
 : < operator when comparing an index key with a search key
 : from $upperBound.
 : @return The set of domain nodes that satisfy the search condition.
 : @error zerr:ZDDY0021 if the index was not declared.
 : @error zerr:ZDDY0023 if the index does not exist.
 : @error zerr:ZDDY0030 if the index is not a general range index.
 : @error err:XPTY0004 if $haveLowerBound is true and
 : $lowerBoundKeys contains an atomic item whose type does not
 : match the sequence type specified by the index keyspec, or
 : $haveUpperBound is true and $upperBoundKeys
 : contains an atomic item whose type does not match the sequence type
 : specified by the index keyspec.
 :)
declare function
idml:probe-index-range-general( $name               as xs:QName,
                                $lowerBound         as xs:anyAtomicType*,
                                $upperBound         as xs:anyAtomicType*,
                                $haveLowerBound     as xs:boolean,
                                $haveUpperBound     as xs:boolean,
                                $lowerBoundIncluded as xs:boolean,
                                $upperBoundIncluded as xs:boolean )
  as node()* external;

(:~
 : Updates the index with the given name.  Note that if the maintenance
 : property of the index is automatic, this function does nothing.
 :
 : @param $name The name of the index to refresh.
 : @return An empty XDM instance and a pending update list that, when applied,
 : refreshes the contents of the index.
 : @error zerr:ZDDY0021 if the index is not declared.
 : @error zerr:ZDDY0023 if the index does not exist.
 :)
declare updating function idml:refresh-index( $name as xs:QName )
  external;

(:~
 : Gets a sequence of all keys contained in the index with the given name.
 : Each element has the following structure:
 :

 :   <key xmlns="http://zorba.io/modules/store/static/indexes/dml">
 :     <attribute value="key1_value"/>
 :     <attribute value="key2_value"/>
 :     <attribute value="key3_value"/>
 :   </key>
 :

 : Note that the order of the attribute elements reflects the order of
 : the keys in the index specification. Also note that the values in
 : these attributes have the type that is declared in the corresponding
 : index specification.
 :
 : @param $name The name of the index to get the keys for.
 : @return A sequence of elements comprising the keys in the index.
 : @error zerr:ZDDY0021 if the index was not declared.
 : @error zerr:ZDDY0023 if the index does not exist.
 :)
declare function idml:keys( $name as xs:QName )
  as node()* external;

(:===========================================================================:)

(: vim:set et sw=2 ts=2: :)


XQTS: minor changes, fighting default and empty namespaces

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

(: declare default element namespace "http://www.w3.org/2005/02/query-test-XQTSResult"; :)
declare option exist:serialize "method=xml indent=yes";
declare option exist:output-size-limit "-1";
declare namespace response="http://exist-db.org/xquery/response";

let $product-version := util:system-property("product-version")
let $product-build := util:system-property("product-build")
let $test-suite := doc('/db/XQTS/XQTSCatalog.xml')/*:test-suite/@version
let $dummy := response:set-header("Content-Disposition", concat(
	"attachment; filename="results_XQTS-" , $test-suite , "_eXist-" ,
	$product-version , '_' , $product-build , ".xml"" ) )

return
<test-suite-result>
        <implementation name="eXist-{$product-version}" version="{$product-build}" anonymous-result-column="false">

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

                <submittor name="eXist XQTS testsuite runner" email="xqts@exist-db.org"/>

                <description>

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

                </description>

                <implementation-defined-items>

                </implementation-defined-items>

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

                <context-properties>

                </context-properties>

        </implementation>

        <syntax>XQuery</syntax>

        <test-run dateRun="{fn:current-dateTime()}">
                <test-suite version="{$test-suite}"/>
                <transformation>

No unusual transformations.

                </transformation>
                <comparison>

No unusual comparisons

                </comparison>
                <otherComments>

The test run took n seconds.

                </otherComments>
        </test-run>

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

declare option exist:serialize "method=xml indent=yes";
declare option exist:output-size-limit "-1";
declare namespace response="http://exist-db.org/xquery/response";

let $product-version := util:system-property("product-version")
let $product-build := util:system-property("product-build")
let $test-suite := doc('/db/XQTS/XQTSCatalog.xml')/*:test-suite/@version
let $dummy := response:set-header("Content-Disposition", concat(
	"attachment; filename="results_XQTS-" , $test-suite , "_eXist-" ,
	$product-version , '_' , $product-build , ".xml"" ) )

return
<test-suite-result xmlns="http://www.w3.org/2005/02/query-test-XQTSResult"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

        <implementation name="eXist-{$product-version}" version="{$product-build}" anonymous-result-column="false">

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

                <submittor name="eXist XQTS testsuite runner" email="xqts@exist-db.org"/>

                <description>

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

                </description>

                <implementation-defined-items>

                </implementation-defined-items>

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

                <context-properties>

                </context-properties>

        </implementation>

        <syntax>XQuery</syntax>

        <test-run dateRun="{fn:current-dateTime()}">
                <test-suite version="{$test-suite}"/>
                <transformation>

No unusual transformations.

                </transformation>
                <comparison>

No unusual comparisons

                </comparison>
                <otherComments>

The test run took n seconds.

                </otherComments>
        </test-run>

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


change to localhost

change to localhost

xquery version "3.1";

module namespace support="http://exist-db.org/ext/mongodb/test/support";

import module namespace mongodb = "http://exist-db.org/xquery/mongodb"
                at "java:org.exist.mongodb.xquery.MongodbModule";

declare variable $support:mongoUrl := "mongodb://localhost";
declare variable $support:database := "mydatabase";
declare variable $support:testCollection := "/db/mongodbTest";
declare variable $support:mongoCollection := "mongodbTest";
declare variable $support:tokenStore := "token.xml";

(:
 : Connect to mongodb, store token
 :)
declare function support:setup() {
    let $foo :=  xmldb:create-collection("/db", "mongodbTest")
    let $token := mongodb:connect($support:mongoUrl)
    return xmldb:store($support:testCollection, $support:tokenStore, <token>{$token}</token>)
};

(:
 : Disconnect from mongodb, cleanup token
 :)
declare function support:cleanup() {
    let $mongodbClientId := support:getToken()
    let $drop := mongodb:drop($mongodbClientId, $support:database, $support:mongoCollection)
    let $logout := mongodb:close($mongodbClientId)
    return
    xmldb:remove($support:testCollection)
};

(:
 : Get token from store
 :)
declare function support:getToken() as xs:string {
    doc($support:testCollection || "/" || $support:tokenStore )//token/text()
};

xquery version "3.1";

module namespace support="http://exist-db.org/ext/mongodb/test/support";

import module namespace mongodb = "http://exist-db.org/xquery/mongodb"
                at "java:org.exist.mongodb.xquery.MongodbModule";

declare variable $support:mongoUrl := "mongodb://miniserver.local";
declare variable $support:database := "mydatabase";
declare variable $support:testCollection := "/db/mongodbTest";
declare variable $support:mongoCollection := "mongodbTest";
declare variable $support:tokenStore := "token.xml";

(:
 : Connect to mongodb, store token
 :)
declare function support:setup() {
    let $foo :=  xmldb:create-collection("/db", "mongodbTest")
    let $token := mongodb:connect($support:mongoUrl)
    return xmldb:store($support:testCollection, $support:tokenStore, <token>{$token}</token>)
};

(:
 : Disconnect from mongodb, cleanup token
 :)
declare function support:cleanup() {
    let $mongodbClientId := support:getToken()
    let $drop := mongodb:drop($mongodbClientId, $support:database, $support:mongoCollection)
    let $logout := mongodb:close($mongodbClientId)
    return
    xmldb:remove($support:testCollection)
};

(:
 : Get token from store
 :)
declare function support:getToken() as xs:string {
    doc($support:testCollection || "/" || $support:tokenStore )//token/text()
};


Added TODOs for SVG example

Added TODOs for SVG example

xquery version "3.1";

(: TODO: handle svg:text :)
(: TODO: compose/collage SVG :)

(: http://limpet.net/mbrubeck/2014/09/08/toy-layout-engine-5-boxes.html :)
(: https://github.com/tel/frame :)
(: https://github.com/tel/frame/blob/master/src/frame/fstate.clj :)
(: http://www.ibm.com/developerworks/library/j-treevisit/ :)
(: https://github.com/akhudek/zip-visit :)

module namespace ex = 'http://xokomola.com/xquery/origami/examples';

import module namespace o = 'http://xokomola.com/xquery/origami'
    at '../../origami/origami.xqm';

(:~
 : A simple function that can be used with a walker to report the tag of
 : each element.
 :)
declare function ex:report($node)
{
    let $report := trace(o:tag($node), 'TAG: ')
    return
        $node
};

(:~
 : Copy an element node setting width and height attributes only
 : if not set.
 :)
declare function ex:advise-dimensions($node, $width, $height)
as array(*)
{
    array {
        o:tag($node),
        o:advise-attrs($node, map {
            'width': $width,
            'height': $height
        }),
        o:children($node)
    }
};

(:~
 : Iterate over a sequence of elements and returning a specific attribute
 : for each element.
 :)
(: TODO: why an array? :)
declare function ex:collect-attribute($nodes, $attribute as xs:string)
as array(*)
{
    fold-left(
        $nodes,
        [],
        function($result,$item) {
            array:append($result,o:attrs($item)($attribute))
        }
    )
};

(: TODO: if an array why not just use array:size? :)
declare function ex:count-values($values as array(*))
as xs:integer
{
    count($values?*)
};

(:~
 : Map over an array of integers adding up all previous values returning
 : a new array with all values.
 :)
(: TODO: why an array? :)
declare function ex:sum-values($values as array(*))
{
    let $values := $values?*
    return
        array {
            fold-left($values,(0),
                function($result,$item) {
                    ($result, sum($result[last()] + $item))
                }
            )
        }
};

(: TODO: not very clear :)
declare function ex:advise-values($a,$b)
{
    let $b :=
        if ($b instance of array(*)) then
            $b
        else
            array { for $i in 1 to array:size($a) return $b }
    return
        array:for-each-pair($a,$b, function($a,$b) { ($a,$b)[1] })
};

(: TODO: how to get rid of code duplication for vbox/hbox :)
declare function ex:layout-node-children($node)
{
    let $tag := o:tag($node)
    let $attrs := o:attrs($node)
    let $children := o:children($node)
    let $child-count := count($children)
    let $width := $attrs?width
    let $height := $attrs?height
    let $x := ($attrs?x, 0)[1]
    let $y := ($attrs?y, 0)[1]
    return
        if (starts-with($tag,'svg:')) then
            $node
        else
            array {
                $tag,
                $attrs,
                if ($child-count = 0) then
                    ()
                else if (every $node in o:filter($children, o:is-element#1)
                            satisfies o:tag($node) = 'layer') then
                    fold-left(
                        $children,
                        (),
                        function($result, $child) {
                            ($result, $child => o:set-attrs(map {
                                'x': $x,
                                'y': $y,
                                'height': $height,
                                'width': $width
                            }))
                        }
                    )
                else if ($tag = 'hbox') then
                    let $child-widths := ex:collect-attribute($children,'width')
                    let $advised-width :=
                        ($width - sum($child-widths))
                        div ($child-count - ex:count-values($child-widths))
                    let $advice := ex:advise-values($child-widths, $advised-width)
                    let $x := ex:sum-values($advice)
                    return
                        fold-left(
                            $children,
                            (),
                            function($result, $child) {
                                let $pos := count($result) + 1
                                return
                                    ($result, $child => o:set-attrs(map {
                                        'x': $x($pos),
                                        'y': $y,
                                        'height': (o:attrs($child)?height,$height)[1],
                                        'width': $advice($pos)
                                    }))
                            }
                        )
                else
                    let $child-heights := ex:collect-attribute($children,'height')
                    let $advised-height :=
                        ($height - sum($child-heights))
                        div ($child-count - ex:count-values($child-heights))
                    let $advice := ex:advise-values($child-heights, $advised-height)
                    let $y := ex:sum-values($advice)
                    return
                        fold-left(
                            $children,
                            (),
                            function($result, $child) {
                                let $pos := count($result) + 1
                                return
                                    ($result, $child => o:set-attrs(map {
                                        'x': $x,
                                        'y': $y($pos),
                                        'height': $advice($pos),
                                        'width': (o:attrs($child)?width,$width)[1]
                                    }))
                            }
                        )
            }
};

declare function ex:layout-node($node)
{
    let $tag := o:tag($node)
    let $attrs := o:attrs($node)
    let $children := o:children($node)
    let $height := 40
    let $width := 100
    return
        if (count($children) = 0) then
            ex:advise-dimensions($node,
                $width,
                $height
            )
        else if ($tag = 'hbox') then
            ex:advise-dimensions($node,
                sum(o:for-each($children, function($n) { o:attrs($n)?width })),
                max(o:for-each($children, function($n) { o:attrs($n)?height }))
            )
        else
            ex:advise-dimensions($node,
                max(o:for-each($children, function($n) { o:attrs($n)?width })),
                sum(o:for-each($children, function($n) { o:attrs($n)?height }))
            )
};
declare function ex:layout-top-down($mu)
{
    o:prewalk($mu, ex:layout-node-children#1)
};

declare function ex:layout-bottom-up($mu)
{
    o:postwalk($mu, ex:layout-node#1)
};

declare function ex:render-svg-node($node)
{
    let $tag := o:tag($node)
    let $attrs := o:attrs($node)
    let $children := o:children($node)
    where $tag != 'spacer'
    return (
        if (starts-with($tag,'svg:')) then
            array { substring-after($tag,'svg:'), $attrs, $children }
        else if ($tag != 'layer') then
            (
                array { 'rect',
                    $node =>
                    o:advise-attrs(map {
                            'fill': ex:rgb(),
                            'fill-opacity': 0.6,
                            'stroke-width': 1,
                            'stroke': 'black',
                            'stroke-opacity': 1
                    }) =>
                    o:remove-attr('layers') =>
                    o:attrs()
                },
                $children
            )
        else
            array { 'g',
                $attrs?id,
                $children
            }
    )
};

declare function ex:rgb()
{
    'rgb(' || string-join((1 to 3) ! random:integer(255), ',') || ')'
};

(: TODO: maybe instead use o:transformer :)

declare function ex:svg-builder()
{
    o:ns-builder((
        ['v', 'http://xokomola.com/xquery/collage'],
        ['svg', 'http://www.w3.org/2000/svg'],
        ['', 'http://www.w3.org/2000/svg']
    ))
};

declare function ex:svg($mu)
{
    let $layers := tokenize(o:attrs($mu)?layers,'\s+')
    return
        ['svg',
            o:sort(
                o:postwalk($mu, ex:render-svg-node#1),
                function($node) {
                    if (o:tag($node) = 'g') then
                        index-of($layers, (o:attrs($node)?id,-10)[1])
                    else
                        -10
                }
            )
        ]
};

(:~
 : Generate an $i x $j grid with random colors.
 :)
declare function ex:mosaic($i,$j)
{
    let $cell-width := 100
    return
        ['vbox',
            map { 'width': $i * $cell-width, 'height': $j * $cell-width },
            for $row in 1 to $i
            return
                ['hbox',
                    for $col in 1 to $j
                    return
                        ['box']
                ]
        ]
};

xquery version "3.1";

(: TODO: handle svg:text :)
(: TODO: compose/collage SVG :)

(: http://limpet.net/mbrubeck/2014/09/08/toy-layout-engine-5-boxes.html :)
(: https://github.com/tel/frame :)
(: https://github.com/tel/frame/blob/master/src/frame/fstate.clj :)
(: http://www.ibm.com/developerworks/library/j-treevisit/ :)
(: https://github.com/akhudek/zip-visit :)

module namespace ex = 'http://xokomola.com/xquery/origami/examples';

import module namespace o = 'http://xokomola.com/xquery/origami'
    at '../../origami/origami.xqm';

declare function ex:report($node)
{
    let $report := trace(o:tag($node), 'TAG: ')
    return
        $node
};

declare function ex:advise-dimensions($node, $width, $height)
as array(*)
{
    array {
        o:tag($node),
        o:advise-attrs($node, map {
            'width': $width,
            'height': $height
        }),
        o:children($node)
    }
};

declare function ex:collect-attribute($nodes, $attribute as xs:string)
as array(*)
{
    fold-left(
        $nodes,
        [],
        function($result,$item) {
            array:append($result,o:attrs($item)($attribute))
        }
    )
};

declare function ex:count-values($values as array(*))
as xs:integer
{
    count($values?*)
};

declare function ex:sum-values($values as array(*))
{
    let $values := $values?*
    return
        array {
            fold-left($values,(0),
                function($result,$item) {
                    ($result, sum($result[last()] + $item))
                }
            )
        }
};

declare function ex:advise-values($a,$b)
{
    let $b :=
        if ($b instance of array(*)) then
            $b
        else
            array { for $i in 1 to array:size($a) return $b }
    return
        array:for-each-pair($a,$b, function($a,$b) { ($a,$b)[1] })
};

declare function ex:layout-node-children($node)
{
    let $tag := o:tag($node)
    let $attrs := o:attrs($node)
    let $children := o:children($node)
    let $child-count := count($children)
    let $width := $attrs?width
    let $height := $attrs?height
    let $x := ($attrs?x, 0)[1]
    let $y := ($attrs?y, 0)[1]
    return
        if (starts-with($tag,'svg:')) then
            $node
        else
            array {
                $tag,
                $attrs,
                if ($child-count = 0) then
                    ()
                else if (every $node in o:filter($children, o:is-element#1)
                            satisfies o:tag($node) = 'layer') then
                    fold-left(
                        $children,
                        (),
                        function($result, $child) {
                            ($result, $child => o:set-attrs(map {
                                'x': $x,
                                'y': $y,
                                'height': $height,
                                'width': $width
                            }))
                        }
                    )
                else if ($tag = 'hbox') then
                    let $child-widths := ex:collect-attribute($children,'width')
                    let $advised-width :=
                        ($width - sum($child-widths))
                        div ($child-count - ex:count-values($child-widths))
                    let $advice := ex:advise-values($child-widths, $advised-width)
                    let $x := ex:sum-values($advice)
                    return
                        fold-left(
                            $children,
                            (),
                            function($result, $child) {
                                let $pos := count($result) + 1
                                return
                                    ($result, $child => o:set-attrs(map {
                                        'x': $x($pos),
                                        'y': $y,
                                        'height': (o:attrs($child)?height,$height)[1],
                                        'width': $advice($pos)
                                    }))
                            }
                        )
                else
                    let $child-heights := ex:collect-attribute($children,'height')
                    let $advised-height :=
                        ($height - sum($child-heights))
                        div ($child-count - ex:count-values($child-heights))
                    let $advice := ex:advise-values($child-heights, $advised-height)
                    let $y := ex:sum-values($advice)
                    return
                        fold-left(
                            $children,
                            (),
                            function($result, $child) {
                                let $pos := count($result) + 1
                                return
                                    ($result, $child => o:set-attrs(map {
                                        'x': $x,
                                        'y': $y($pos),
                                        'height': $advice($pos),
                                        'width': (o:attrs($child)?width,$width)[1]
                                    }))
                            }
                        )
            }
};

declare function ex:layout-node($node)
{
    let $tag := o:tag($node)
    let $attrs := o:attrs($node)
    let $children := o:children($node)
    let $height := 40
    let $width := 100
    return
        if (count($children) = 0) then
            ex:advise-dimensions($node,
                $width,
                $height
            )
        else if ($tag = 'hbox') then
            ex:advise-dimensions($node,
                sum(o:for-each($children, function($n) { o:attrs($n)?width })),
                max(o:for-each($children, function($n) { o:attrs($n)?height }))
            )
        else
            ex:advise-dimensions($node,
                max(o:for-each($children, function($n) { o:attrs($n)?width })),
                sum(o:for-each($children, function($n) { o:attrs($n)?height }))
            )
};
declare function ex:layout-top-down($mu)
{
    o:prewalk($mu, ex:layout-node-children#1)
};

declare function ex:layout-bottom-up($mu)
{
    o:postwalk($mu, ex:layout-node#1)
};

declare function ex:render-svg-node($node)
{
    let $tag := o:tag($node)
    let $attrs := o:attrs($node)
    let $children := o:children($node)
    where $tag != 'spacer'
    return (
        if (starts-with($tag,'svg:')) then
            array { substring-after($tag,'svg:'), $attrs, $children }
        else if ($tag != 'layer') then
            (
                array { 'rect',
                    $node =>
                    o:advise-attrs(map {
                            'fill': ex:rgb(),
                            'fill-opacity': 0.6,
                            'stroke-width': 1,
                            'stroke': 'black',
                            'stroke-opacity': 1
                    }) =>
                    o:remove-attr('layers') =>
                    o:attrs()
                },
                $children
            )
        else
            array { 'g',
                $attrs?id,
                $children
            }
    )
};

declare function ex:rgb()
{
    'rgb(' || string-join((1 to 3) ! random:integer(255), ',') || ')'
};

(: TODO: maybe instead use o:transformer :)

declare function ex:svg-builder()
{
    o:ns-builder((
        ['v', 'http://xokomola.com/xquery/collage'],
        ['svg', 'http://www.w3.org/2000/svg'],
        ['', 'http://www.w3.org/2000/svg']
    ))
};

declare function ex:svg($mu)
{
    let $layers := tokenize(o:attrs($mu)?layers,'\s+')
    return
        ['svg',
            o:sort(
                o:postwalk($mu, ex:render-svg-node#1),
                function($node) {
                    if (o:tag($node) = 'g') then
                        index-of($layers, (o:attrs($node)?id,-10)[1])
                    else
                        -10
                }
            )
        ]
};

(:~
 : Generate an $i x $j grid with random colors.
 :)
declare function ex:mosaic($i,$j)
{
    let $cell-width := 100
    return
        ['vbox',
            map { 'width': $i * $cell-width, 'height': $j * $cell-width },
            for $row in 1 to $i
            return
                ['hbox',
                    for $col in 1 to $j
                    return
                        ['box']
                ]
        ]
};


Annotate the Saxon saxon functions with versioned type restrictions.

xquery version "3.1";
(:~
 : Saxon extension functions
 : @see http://www.saxonica.com/html/documentation/functions/saxon
 :
 :)
module namespace saxon = "http://saxon.sf.net/";

declare namespace jt = "http://saxon.sf.net/java-type";
declare namespace xsl = "http://www.w3.org/1999/XSL/Transform";

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

declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:adjust-to-civil-time($in as xs:dateTime, $tz as xs:string) as xs:dateTime? external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:array-member($value as item()*) as jt:com.saxonica.functions.extfn.ArrayMemberValue external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:base64Binary-to-octets($input as xs:base64Binary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:base64Binary-to-string($input as xs:base64Binary?, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number() as xs:integer external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:compile-query($query as xs:string) as jt:net.sf.saxon.query.XQueryExpression external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:compile-stylesheet($stylesheet as document-node()) as jt.net.sf.saxon.PreparedStylesheet external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:decimal-divide($arg1 as xs:decimal?, $arg2 as xs:decimal, $precision as xs:integer) as xs:decimal? external;
declare %a:since("saxon/pe", "8.6.1") %a:since("saxon/ee", "8.6.1") function saxon:deep-equal($arg1 as item()*, $arg2 as item()*, $collation as xs:string?, $flags as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:discard-document($doc as document-node()) as document-node() external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:doc($href as xs:string, $options as map(*)) as document-node() external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:eval($stored-expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $param1 as item()*, $param2 as item()*, $param3 as item()*) as xs:double external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:evaluate($xpath as xs:string, $param1 as item()*, $param2 as item()*, $param3 as item()*) as item()* external;
declare %a:since("saxon/pe", "8.2") %a:since("saxon/ee", "8.2") function saxon:evaluate-node($node as node()) as item()* external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string, $ns as element()) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:function-annotations($fn as function(*)) as map(*)* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:get-pseudo-attribute($att as xs:string) as xs:string? external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:group-starting($input as item()*, $condition as function(item()) as xs:boolean) as array(item()*)+ external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:has-same-nodes($arg1 as node()*, $arg2 as node()*) as xs:boolean external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:hexBinary-to-octets($input as xs:hexBinary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:hexBinary-to-string($input as xs:hexBinary, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*) as item()* external;
declare %a:restrict-until("$key", "saxon/pe", "9.2", "jt:net.sf.saxon.functions.Evaluate-PreparedExpression")
        %a:restrict-until("$key", "saxon/ee", "9.2", "jt:net.sf.saxon.functions.Evaluate-PreparedExpression")
        %a:restrict-since("$key", "saxon/pe", "9.2", "function(*)")
        %a:restrict-since("$key", "saxon/ee", "9.2", "function(*)")
        %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*, $key as (jt:net.sf.saxon.functions.Evaluate-PreparedExpression|function(*))) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:in-summer-time($date as xs:dateTime, $region as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.3") %a:since("saxon/ee", "8.3") %a:until("saxon/pe", "9.4") %a:until("saxon/ee", "9.4") function saxon:index($sequence as item()*, $expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $collation as xs:string) as jt:com.saxonica.expr.IndexedSequence external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:index($sequence as item()*, $function as function(item()) as xs:anyAtomicType*) as map(*) external;
declare %a:since("saxon/ee", "9.7") function saxon:is-defaulted($node as node()) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:is-whole-number($arg as xs:numeric?) as xs:boolean external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") %a:until("saxon/pe", "9.1") %a:until("saxon/ee", "9.1") function saxon:last-modified() as xs:dateTime? external;
declare %a:restrict-until("$file-or-uri", "saxon/pe", "9.2", "node()")
        %a:restrict-until("$file-or-uri", "saxon/ee", "9.2", "node()")
        %a:restrict-since("$file-or-uri", "saxon/pe", "9.2", "xs:string?")
        %a:restrict-since("$file-or-uri", "saxon/ee", "9.2", "xs:string?")
        %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:last-modified($file-or-uri as (xs:string?|node())) as xs:dateTime? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*) as item() external;
declare %a:restrict-until("$test", "saxon/pe", "9.5", "jt:net.sf.saxon.functions.Evaluate-PreparedExpression")
        %a:restrict-until("$test", "saxon/ee", "9.5", "jt:net.sf.saxon.functions.Evaluate-PreparedExpression")
        %a:restrict-since("$test", "saxon/pe", "9.5", "function(*)")
        %a:restrict-since("$test", "saxon/ee", "9.5", "function(*)")
        %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*, $test as (jt:net.sf.saxon.functions.Evaluate-PreparedExpression|function(*))) as item() external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number() as xs:integer external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*) as item()* external;
declare %a:restrict-until("$key", "saxon/pe", "9.2", "jt:net.sf.saxon.functions.Evaluate-PreparedExpression")
        %a:restrict-until("$key", "saxon/ee", "9.2", "jt:net.sf.saxon.functions.Evaluate-PreparedExpression")
        %a:restrict-since("$key", "saxon/pe", "9.2", "function(*)")
        %a:restrict-since("$key", "saxon/ee", "9.2", "function(*)")
        %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*, $key as (jt:net.sf.saxon.functions.Evaluate-PreparedExpression|function(*))) as item()* external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:map-search($input as item()*, $key as xs:anyAtomicType) as map(*)* external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:map-search($input as item()*, $key as xs:anyAtomicType, $condition as function(item()) as xs:boolean) as map(*)* external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:message-count($errCode as xs:QName?) as xs:integer external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") %a:deprecated("saxon/pe", "9.2") %a:deprecated("saxon/ee", "9.2") function saxon:namespace-node($prefix as xs:string, $uri as xs:string) as namespace-node() external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:object-map($object as jt:java.lang.Object) as map(xs:string, function(*)) external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-base64Binary($octets as xs:integer*) as xs:base64Binary external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-hexBinary($octets as xs:integer*) as xs:hexBinary external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:parse-xml") function saxon:parse($xml as xs:string) as document-node() external;
declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:parse-html($html as xs:string) as document-node() external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path() as xs:string external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path($node as node()) as xs:string external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:pedigree($in as function(*)) as tuple(container: function(*), key: anyAtomicType?, index: xs:integer?)? external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:print-stack() as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?, $params as node()*) as item()* external;
declare %a:since("saxon/pe", "9.7") %a:since("saxon/ee", "9.7") function saxon:read-binary-resource($uri as xs:string) as xs:base64Binary external;
declare %a:since("saxon/ee", "9.5") function saxon:schema() as function(*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:schema($kind as xs:string, $name as xs:QName) as function(*)? external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item()) as xs:boolean external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item(), $attachment as item()*) as xs:boolean external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as xs:string) as xs:string external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as element(xsl:output)) as xs:string external;
declare %a:since("saxon/pe", "8.9") %a:since("saxon/ee", "8.9") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*) as item()* external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*, $sort-key as function(item()) as xs:anyAtomicType) as item()* external;
declare %a:since("saxon/ee", "8.0") function saxon:stream($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-base64Binary($in as xs:string?, $encoding as xs:string) as xs:base64Binary? external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-hexBinary($in as xs:string?, $encoding as xs:string) as xs:hexBinary? external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:string-to-utf8($name as xs:string) as xs:integer* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:system-id() as xs:string external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:timestamp() as xs:dateTimeStamp external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node()) as document-node() external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node(), $params as item()*) as document-node() external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:type($item as item()?) as function(*)? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:type-annotation($item as item()?) as xs:QName? external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:unparsed-entities($doc as document-node()) as xs:string* external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*)) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*), $params as map(xs:string, item()*)) as map(xs:string, item()*)? external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:with-pedigree($in as function(*)) as function(*) external;

xquery version "3.1";
(:~
 : Saxon extension functions
 : @see http://www.saxonica.com/html/documentation/functions/saxon
 :
 :)
module namespace saxon = "http://saxon.sf.net/";

declare namespace jt = "http://saxon.sf.net/java-type";
declare namespace xsl = "http://www.w3.org/1999/XSL/Transform";

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

declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:adjust-to-civil-time($in as xs:dateTime, $tz as xs:string) as xs:dateTime? external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:array-member($value as item()*) as jt:com.saxonica.functions.extfn.ArrayMemberValue external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:base64Binary-to-octets($input as xs:base64Binary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:base64Binary-to-string($input as xs:base64Binary?, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number() as xs:integer external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:column-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:compile-query($query as xs:string) as jt:net.sf.saxon.query.XQueryExpression external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:compile-stylesheet($stylesheet as document-node()) as jt.net.sf.saxon.PreparedStylesheet external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:decimal-divide($arg1 as xs:decimal?, $arg2 as xs:decimal, $precision as xs:integer) as xs:decimal? external;
declare %a:since("saxon/pe", "8.6.1") %a:since("saxon/ee", "8.6.1") function saxon:deep-equal($arg1 as item()*, $arg2 as item()*, $collation as xs:string?, $flags as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:discard-document($doc as document-node()) as document-node() external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:doc($href as xs:string, $options as map(*)) as document-node() external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:eval($stored-expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $param1 as item()*, $param2 as item()*, $param3 as item()*) as xs:double external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:evaluate($xpath as xs:string, $param1 as item()*, $param2 as item()*, $param3 as item()*) as item()* external;
declare %a:since("saxon/pe", "8.2") %a:since("saxon/ee", "8.2") function saxon:evaluate-node($node as node()) as item()* external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "7.2") %a:since("saxon/ee", "7.2") function saxon:expression($string as xs:string, $ns as element()) as jt:net.sf.saxon.functions.Evaluate-PreparedExpression external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:function-annotations($fn as function(*)) as map(*)* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:get-pseudo-attribute($att as xs:string) as xs:string? external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:group-starting($input as item()*, $condition as function(item()) as xs:boolean) as array(item()*)+ external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:has-same-nodes($arg1 as node()*, $arg2 as node()*) as xs:boolean external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:hexBinary-to-octets($input as xs:hexBinary) as xs:integer* external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:hexBinary-to-string($input as xs:hexBinary, $encoding as xs:string) as xs:string external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:highest($input as item()*, $key as function(*) (: $key [8.1] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.2] as function() [9.5] as function(*) :)) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:in-summer-time($date as xs:dateTime, $region as xs:string) as xs:boolean external;
declare %a:since("saxon/pe", "8.3") %a:since("saxon/ee", "8.3") %a:until("saxon/pe", "9.4") %a:until("saxon/ee", "9.4") function saxon:index($sequence as item()*, $expression as jt:net.sf.saxon.functions.Evaluate-PreparedExpression, $collation as xs:string) as jt:com.saxonica.expr.IndexedSequence external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:index($sequence as item()*, $function as function(item()) as xs:anyAtomicType* (: [9.5] as xs:integer  :)) as map(*) (: [8.3] as jt:com.saxonica.expr.IndexedSequence [9.5] as xs:double [9.7] as map(*) :) external;
declare %a:since("saxon/ee", "9.7") function saxon:is-defaulted($node as node()) as xs:boolean external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:is-whole-number($arg as xs:numeric?) as xs:boolean external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") function saxon:last-modified($uri as xs:string? (: [9.0] () as document-uri($node)) [9.2] $uri as xs:string? :)) as xs:dateTime? external;
declare %a:since("saxon/pe", "9.0") %a:since("saxon/ee", "9.0") %a:until("saxon/pe", "9.1") %a:until("saxon/ee", "9.1") function saxon:last-modified($node as node()) as xs:dateTime? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*) as item() external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:leading($input as item()*, $test as function(*) (: [8.0] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.5] as function(*) :)) as item() external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number() as xs:integer external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:line-number($node as node()) as xs:integer external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.1") function saxon:lowest($input as item()*, $key as function(*) (: $key [8.0] as jt:net.sf.saxon.functions.Evaluate-PreparedExpression [9.2] as function() [9.5] as function(*) :)) as item()* external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:map-search($input as item()*, $key as xs:anyAtomicType) as map(*)* external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:map-search($input as item()*, $key as xs:anyAtomicType, $condition as function(item()) as xs:boolean) as map(*)* external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:message-count($errCode as xs:QName?) as xs:integer external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") %a:deprecated("saxon/pe", "9.2") %a:deprecated("saxon/ee", "9.2") function saxon:namespace-node($prefix as xs:string, $uri as xs:string) as namespace-node() external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:object-map($object as jt:java.lang.Object) as map(xs:string, function(*)) external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-base64Binary($octets as xs:integer*) as xs:base64Binary external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:octets-to-hexBinary($octets as xs:integer*) as xs:hexBinary external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:parse-xml") function saxon:parse($xml as xs:string) as document-node() external;
declare %a:since("saxon/pe", "9.2") %a:since("saxon/ee", "9.2") function saxon:parse-html($html as xs:string) as document-node() external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path() as xs:string external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") %a:deprecated("saxon/pe", "9.6", "fn:parse-xml") %a:deprecated("saxon/ee", "9.6", "fn:path") function saxon:path($node as node()) as xs:string external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:pedigree($in as function(*)) as tuple(container: function(*), key: anyAtomicType?, index: xs:integer?)? external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:print-stack() as xs:string external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?) as item()* external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:query($name as jt:net.sf.saxon.query.XQueryExpression?, $context-item as item()?, $params as node()*) as item()* external;
declare %a:since("saxon/pe", "9.7") %a:since("saxon/ee", "9.7") function saxon:read-binary-resource($uri as xs:string) as xs:base64Binary external;
declare %a:since("saxon/ee", "9.5") function saxon:schema() as function(*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:schema($kind as xs:string, $name as xs:QName) as function(*)? external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item()) as xs:boolean external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:send-mail($emailConfig as map(*), $subject as xs:string, $content as item(), $attachment as item()*) as xs:boolean external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as xs:string) as xs:string external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:serialize") %a:deprecated("saxon/ee", "9.6", "fn:serialize") function saxon:serialize($node as node(), $format as element(xsl:output)) as xs:string external;
declare %a:since("saxon/pe", "8.9") %a:since("saxon/ee", "8.9") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*) as item()* external;
declare %a:since("saxon/pe", "7.1") %a:since("saxon/ee", "7.1") %a:deprecated("saxon/pe", "9.6", "fn:sort") %a:deprecated("saxon/ee", "9.6", "fn:sort") function saxon:sort($seq as item()*, $sort-key as function(item()) as xs:anyAtomicType) as item()* external;
declare %a:since("saxon/ee", "8.0") function saxon:stream($input as item()*) as item()* external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-base64Binary($in as xs:string?, $encoding as xs:string) as xs:base64Binary? external;
declare %a:since("saxon/pe", "8.4") %a:since("saxon/ee", "8.4") function saxon:string-to-hexBinary($in as xs:string?, $encoding as xs:string) as xs:hexBinary? external;
declare %a:since("saxon/pe", "8.1") %a:since("saxon/ee", "8.1") function saxon:string-to-utf8($name as xs:string) as xs:integer* external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:system-id() as xs:string external;
declare %a:since("saxon/pe", "9.8") %a:since("saxon/ee", "9.8") function saxon:timestamp() as xs:dateTimeStamp external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node()) as document-node() external;
declare %a:since("saxon/pe", "8.5") %a:since("saxon/ee", "8.5") function saxon:transform($stylesheet as jt:net.sf.saxon.PreparedStylesheet, $source as node(), $params as item()*) as document-node() external;
declare %a:since("saxon/pe", "9.5") %a:since("saxon/ee", "9.5") function saxon:type($item as item()?) as function(*)? external;
declare %a:since("saxon/pe", "8.0") %a:since("saxon/ee", "8.0") function saxon:type-annotation($item as item()?) as xs:QName? external;
declare %a:since("saxon/pe", "9.1") %a:since("saxon/ee", "9.1") function saxon:unparsed-entities($doc as document-node()) as xs:string* external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*)) as map(xs:string, item()*)? external;
declare %a:since("saxon/ee", "9.5") function saxon:validate($node as node()?, $options as map(xs:string, item()*), $params as map(xs:string, item()*)) as map(xs:string, item()*)? external;
declare %a:since("saxon/pe", "9.9") %a:since("saxon/ee", "9.9") function saxon:with-pedigree($in as function(*)) as function(*) external;