<?xml version="1.0" encoding="UTF-8"?>
<fos:functions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.w3.org/xpath-functions/spec/namespace fos.xsd"
   xmlns:fos="http://www.w3.org/xpath-functions/spec/namespace">
         
   <fos:global-variables>
      <fos:variable id="v-po" name="po" as="element()"
         >&lt;PurchaseOrder&gt; &lt;line-item&gt;
         &lt;description&gt;Large widget&lt;/description&gt; &lt;price&gt;8.95&lt;/price&gt;
         &lt;quantity&gt;5.0&lt;/quantity&gt; &lt;/line-item&gt; &lt;line-item&gt;
         &lt;description&gt;Small widget&lt;/description&gt; &lt;price&gt;3.99&lt;/price&gt;
         &lt;quantity&gt;2.0&lt;/quantity&gt; &lt;/line-item&gt; &lt;line-item&gt;
         &lt;description&gt;Tiny widget&lt;/description&gt; &lt;price&gt;1.49&lt;/price&gt;a
         &lt;quantity&gt;805&lt;/quantity&gt; &lt;/line-item&gt;
         &lt;/PurchaseOrder&gt;</fos:variable>
      <fos:variable id="v-item1" name="item1" select="$po/line-item[1]"/>
      <fos:variable id="v-item2" name="item2" select="$po/line-item[2]"/>
      <fos:variable id="v-item3" name="item3" select="$po/line-item[3]"/>
   </fos:global-variables>
   
   <!--<fos:record-type id="key-value-pair" extensible="true">
      <fos:summary>
         <p>This record type represents a key and its associated value within an entry of a map.</p>
      </fos:summary>
      <fos:field name="key" type="xs:anyAtomicType" required="true">
         <fos:meaning>
            <p>A key suitable for use in a map entry.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="value" type="item()*" required="true">
         <fos:meaning>
            <p>The value corresponding to the key.</p>
         </fos:meaning>
      </fos:field>
   </fos:record-type>-->
   
   <fos:record-type id="uri-structure-record" extensible="false">
      <fos:summary>
         <p>This record type represents the components of a URI.</p>
      </fos:summary>
      <fos:field name="uri" type="xs:string?" required="false">
         <fos:meaning>
            <p>The original URI. This element is returned by <function>fn:parse-uri</function>,
            but ignored by <function>fn:build-uri</function>.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="scheme" type="xs:string?" required="false">
         <fos:meaning>
            <p>The URI scheme (e.g., “https” or “file”).</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="absolute" type="xs:boolean?" required="false">
         <fos:meaning>
            <p>The URI is an absolute URI.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="hierarchical" type="xs:boolean?" required="false">
         <fos:meaning>
            <p>Whether the URI is hierarchical or not.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="authority" type="xs:string?" required="false">
         <fos:meaning>
            <p>The authority portion of the URI (e.g., “example.com:8080”).</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="userinfo" type="xs:string?" required="false">
         <fos:meaning><p>Any userinfo that was passed as part of the authority.</p></fos:meaning>
      </fos:field>
      <fos:field name="host" type="xs:string?" required="false">
         <fos:meaning><p>The host passed as part of the authority (e.g., “example.com”). </p></fos:meaning>
      </fos:field>
      <fos:field name="port" type="xs:integer?" required="false">
         <fos:meaning><p>The port passed as part of the authority (e.g., “8080”).</p></fos:meaning>
      </fos:field>
      <fos:field name="path" type="xs:string?" required="false">
         <fos:meaning><p>The path portion of the URI.</p></fos:meaning>
      </fos:field>
      <fos:field name="query" type="xs:string?" required="false">
         <fos:meaning><p>Any query string.</p></fos:meaning>
      </fos:field>
      <fos:field name="fragment" type="xs:string?" required="false">
         <fos:meaning><p>Any fragment identifier.</p></fos:meaning>
      </fos:field>
      <fos:field name="path-segments" type="xs:string*" required="false">
         <fos:meaning><p>Parsed and unescaped path segments.</p></fos:meaning>
      </fos:field>
      <fos:field name="query-parameters" type="map(xs:string, xs:string*)?" required="false">
         <fos:meaning><p>Parsed and unescaped query key-value pairs.</p></fos:meaning>
      </fos:field>
      <fos:field name="filepath" type="xs:string?" required="false">
         <fos:meaning><p>The path of the URI, treated as a filepath.</p></fos:meaning>
      </fos:field>
   </fos:record-type>
   
   <fos:record-type id="element-conversion-plan-record" extensible="false">
      <fos:summary>
         <p>This record type represents a plan for converting elements
            to maps during evaluation of <function>fn:element-to-map</function>.</p>
      </fos:summary>
      <fos:field name="layout" 
                 type="enum('empty', 'empty-plus',
                            'simple', 'simple-plus',
                            'list', 'list-plus',
                            'record', 'sequence', 'mixed', 'xml',
                            'error', 'deep-skip')"
                 required="true">
         <fos:meaning>
            <p>Defines the overall strategy for converting the element content.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="child" type="xs:string?" required="false">
         <fos:meaning>
            <p>For list layouts, defines the name of the child element type contained in the list.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="type" type="enum('numeric', 'boolean', 'string')" required="false">
         <fos:meaning>
            <p>For elements with simple content, defines whether they should be represented
               as numbers or booleans instead of the default representation as strings.</p>
         </fos:meaning>
      </fos:field>
   </fos:record-type>
   
   <fos:record-type id="attribute-conversion-plan-record" extensible="false">
      <fos:summary>
         <p>This record type represents a plan for converting attributes
            to atomic items during evaluation of <function>fn:element-to-map</function>.</p>
      </fos:summary>
      <fos:field name="type" type="enum('numeric', 'boolean', 'string', 'skip')" required="true">
         <fos:meaning>
            <p>Defines whether attributes should be represented
               as numbers or booleans instead of the default representation as strings;
               alternatively, indicates that the attribute should be omitted.</p>
         </fos:meaning>
      </fos:field>
   </fos:record-type>

   <fos:record-type id="schema-type-record" extensible="false">
      <fos:summary>
         <p>This record type represents the properties of a simple or complex type in a schema.</p>
      </fos:summary>
      <fos:field name="name" type="xs:QName?" required="true">
         <fos:meaning>
            <p>The name of the type. Empty in the case of an anonymous type. Corresponds to
            <xtermref spec="XS11-1" ref="ctd-name">{name}</xtermref> and 
               <xtermref spec="XS11-1" ref="ctd-target_namespace">{target namespace}</xtermref>
               in the XSD component model for simple and complex type
            components.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="is-simple" type="xs:boolean" required="true">
         <fos:meaning>
            <p>True for a simple type, false for a complex type.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="base-type" type="fn() as schema-type-record?" required="true">
         <fos:meaning>
            <p>Function item returning the base type (the type from which this type is derived by restriction 
               or extension). The function is always present, and returns the empty sequence
               in the case of the type <code>xs:anyType</code>. Corresponds to the 
               <xtermref spec="XS11-1" ref="ctd-base_type_definition">{base type definition}</xtermref> property
            in the XSD component model.</p>
            
         </fos:meaning>
      </fos:field>
      <fos:field name="primitive-type" type="fn() as schema-type-record" required="false">
         <fos:meaning>
            <p>For an atomic type, a function item returning the primitive type from which this 
               type is ultimately derived. Corresponds to the
               <xtermref spec="XS11-1" ref="std-primitive_type_definition">{primitive type definition}</xtermref> in the XSD 
               component model for simple types. Absent if the type is non atomic, or if it is 
               the simple type <code>xs:anyAtomicType</code>. If this is a primitive type, the
               function item is idempotent.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="variety" 
                 required="false" 
                 type='enum("atomic", "list", "union", "empty", "simple", "element-only", "mixed")'>
         <fos:meaning>
            <p>For a simple type, one of <code>"atomic"</code>, <code>"list"</code>, or <code>"union"</code>, corresponding to the
               <xtermref spec="XS11-1" ref="std-variety">{variety}</xtermref> of the simple type in the XSD component model. For a complex type, one of
            <code>"empty"</code>, <code>"simple"</code>, <code>"element-only"</code>, or <code>"mixed"</code>, 
               corresponding to the <xtermref spec="XS11-1" ref="ctd-content_type">{content type}</xtermref>.<xtermref spec="XS11-1" ref="ct-variety">{variety}</xtermref> 
               of the complex type in the XSD component model. The value is absent in cases where the 
            <xtermref spec="XS11-1" ref="std-variety">{variety}</xtermref> in the XSD component model is absent, for example
            for the type <code>xs:anySimpleType</code>.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="members" required="false" type="fn() as schema-type-record*">
         <fos:meaning>
            <p>For a simple type with variety <code>"union"</code>, a function that returns a sequence of
               records representing the member types of the union, in order, corresponding to the
               <xtermref spec="XS11-1" ref="std-member_type_definitions">{member type definitions}</xtermref>
               property in the XSD component model. 
               For a simple type with variety <code>"list"</code>,
            a function that returns a record representing the item type of the list type, corresponding to
            the <xtermref spec="XS11-1" ref="std-item_type_definition">{item type definition}</xtermref> property in the XSD component model. In all other cases, absent.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="simple-content-type" required="false" type="fn() as schema-type-record">
         <fos:meaning>
            <p>For a complex type with variety <code>"simple"</code> (that is, a complex type with simple content), 
               a function that returns a record representing the relevant simple type, corresponding to 
               the <xtermref spec="XS11-1" ref="ctd-content_type">{content type}</xtermref>.<xtermref spec="XS11-1" ref="ct-simple_type_definition">{simple type definition}</xtermref>              
               property in the XSD complex type component. 
               In all other cases, absent.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="matches" type="fn(xs:anyAtomicType) as xs:boolean" required="false">
         <fos:meaning>
            <p>For a <xtermref spec="XP40" ref="dt-generalized-atomic-type"/>, 
               a function item that can be called to establish whether the supplied atomic item
               is an instance of this type. In all other cases, absent.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="constructor" type="fn(xs:anyAtomicType?) as xs:anyAtomicType*" required="false">
         <fos:meaning>
            <p>For a simple type, a function item that can be used to construct instances of this type. In the case of a named
             type that is present in the dynamic context, the result is the same function as returned by 
               <function>fn:function-lookup</function> applied to the type name (with arity one). 
               For details see <specref ref="constructor-functions-for-xsd-types"/>
               and <specref ref="constructor-functions-for-user-defined-types"/>. 
               Constructor function items are also available for
               anonymous types, and for types that might not be present in the dynamic context. 
               The field is absent for complex types and for the abstract types <code>xs:anyAtomicType</code>,
               <code>xs:anySimpleType</code>, and
               <code>xs:NOTATION</code>. It is also absent for all <xtermref spec="XP40" ref="dt-namespace-sensitive"/> types.
            </p>
         </fos:meaning>
      </fos:field>
      <!--<fos:field name="validate" type="fn((document-node()|element())) as (document-node()|element())" required="true">
         <fos:meaning>
            <p>A function item that can be called to validate a supplied document or element node against this type.
            The effect is equivalent to the XQuery expression <code>validate type T {$node}</code> where <var>T</var>
            is this type, and <code>$node</code> is the node supplied as the argument to the function. 
               (See <xspecref spec="XQ40" ref="id-validate"/>.) If validation succeeds,
            the validated node is returned; if it fails (for any reason, including the fact that the processor does
            not support schema validation) then an error is raised, as with the equivalent XQuery expression.</p>
         </fos:meaning>
      </fos:field>
      <fos:field name="valid" type="fn((document-node( )|element())) as xs:boolean" required="true">
         <fos:meaning>
            <p>A function item that can be called to validate a supplied document or element node against this type,
            returning <code>true</code> if validation succeeds, or <code>false</code> if it fails. The function
            call <code>$type?valid($node)</code> is equivalent to the XQuery expression:</p>
            <eg>try { exists( $type?validate($node) ) } catch * { false() }</eg>
         </fos:meaning>
      </fos:field>-->
   </fos:record-type>
   
   <fos:record-type id="load-xquery-module-record" extensible="false">
      <fos:summary>
         <p>This record type is used to hold the result of the <function>fn:load-xquery-module</function> function.</p>
      </fos:summary>
      <fos:field name="variables" type="map(xs:QName, item()*)" required="true">
         <fos:meaning>
                   global variable declared in the library module. The key of the
                 <p>This map (<var>V</var> ) contains one entry for each public
                  entry is the name of the variable, as an <code>xs:QName</code>
                  value; the associated value is the value of the variable.</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="functions" type="map(xs:QName, map(xs:integer, function(*)))" required="true">
         <fos:meaning>
            <p>This map (<var>F</var> ) contains one entry for each distinct QName
            <var>Q</var> that represents the name of a public and non-external
            function declared in the library module. The key of the entry is
            <var>Q</var>, as an <code>xs:QName</code> value; the associated value
            is a map <var>A</var>. This map (<var>A</var>) contains one entry for
            each arity <var>N</var> within the arity range of any of the function
            declarations with the given name; its key is <var>N</var>, as an
            <code>xs:integer</code> value, and its associated value is a function
            item obtained as if by evaluating a named function reference
            <code>Q#N</code>, using the static and dynamic context of the call on
            <function>fn:load-xquery-module</function>. The function item can be invoked
            using the rules for dynamic function invocation.</p>
         </fos:meaning>         
      </fos:field>
   </fos:record-type>
   
   <fos:record-type id="dateTime-record" extensible="false">
      <fos:summary>
         <p>This record type is used to represent the components of a value of type <code>xs:dateTime</code>,
            <code>xs:date</code>, <code>xs:time</code>, <code>xs:gYear</code>, <code>xs:gYearMonth</code>,
            <code>xs:gMonth</code>, <code>xs:gMonthDay</code>, or <code>xs:gDay</code>.</p>
      </fos:summary>
      <fos:field name="year" type="xs:integer" required="false">
         <fos:meaning>
            <p>The value of the <code>year</code> component. Range is implementation-defined.
            If years less than one are supported, then the integer zero represents the year
            before year one, and the integer -1 represents the year before year zero.</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="month" type="xs:integer" required="false">
         <fos:meaning>
            <p>The value of the <code>month</code> component. A valid value is in the range 1 to 12 inclusive.</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="day" type="xs:integer" required="false">
         <fos:meaning>
            <p>The value of the <code>day</code> component. A valid value is in the range 1 to 31 inclusive.</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="hours" type="xs:integer" required="false">
         <fos:meaning>
            <p>The value of the <code>hours</code> component. A valid value is in the range 0 to 23 inclusive.</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="minutes" type="xs:integer" required="false">
         <fos:meaning>
            <p>The value of the <code>minutes</code> component. A valid value is in the range 0 to 59 inclusive.</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="seconds" type="xs:decimal" required="false">
         <fos:meaning>
            <p>The value of the <code>seconds</code> component. A valid value is in the range 0 (inclusive) to 60 (exclusive).</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="timezone" type="xs:dayTimeDuration" required="false">
         <fos:meaning>
            <p>The timezone offset, if the value has a timezone. A valid value corresponds to an integral number
            of minutes between -840 and +840 inclusive.</p>
         </fos:meaning>        
      </fos:field>
   </fos:record-type>
   
   

   
   
   <fos:record-type id="parsed-csv-structure-record" extensible="false">
      <fos:summary>
         <p>This record type is used to hold the result of the <function>fn:parse-csv</function> function.</p>
      </fos:summary>
      <fos:field name="columns" type="xs:string*" required="true">
         <fos:meaning>
               <p>This entry holds a sequence of strings containing column names.
                  The content depends on the setting of the <code>header</code>
                  entry in <code>$options</code>:</p>
               
                  <ulist>
                     <item><p>With <code>"header":false()</code> (which is the default),
                     the value of this entry is the empty sequence.</p></item>
                     <item><p>With <code>"header":true()</code>, the value is a sequence
                     of strings taken from the first row of the data. The strings have
                     leading and trailing whitespace trimmed, regardless of the value of the
                     <code>trim-whitespace</code> option. The sequence
                     of strings will potentially be truncated if the <code>number-of-columns</code>
                     option is specified, and it will potentially be reordered if the
                     <code>filter-columns</code> option is specified. Any strings that are
                     zero-length or duplicated are retained <emph>as-is</emph>.</p>
                    </item>
                     <item><p>If the value of the <code>header</code> option is a sequence
                     of strings, then the value is taken from the supplied sequence.</p>
                     <p>The order of names is <emph>not</emph> adjusted based on the 
                        <code>select-columns</code> 
                        option; the supplied list of names is expected to refer to columns
                        in the result, not to columns in the input.</p></item>
                  </ulist>
         </fos:meaning>
      </fos:field>
      <fos:field name="column-index" type="map(xs:string,xs:integer)?" required="true">
         <fos:meaning>
         
         <p>This entry holds a map from column names (as strings) to
                  column positions (as 1-based positive integers).
                  The content depends on the setting of the <code>header</code>
                  entry in <code>$options</code>:</p>
               
               <ulist>
                  <item><p>With <code>"header":false()</code> (which is the default),
                     the value of this entry is the empty map.</p></item>
                  <item><p>With <code>"header":true()</code>, the map
                     contains entries based on the contents of the first row of the data. 
                     The strings have
                     leading and trailing whitespace trimmed, regardless of the value of the
                     <code>trim-whitespace</code> option. Any string appearing in the header
                     row that is non-zero-length and is not equal (using codepoint collation) to
                     any previous string appearing in the header results in an entry
                     pairing that string to its 1-based position in the header row.</p>
                     <p>If the <code>select-columns</code> 
                     option is present then the entries are adjusted (or removed) to
                     reflect their position in the adjusted data rows.</p>
                     
                    
                  
                  </item>
                  <item><p>If the value of the <code>header</code> option is a 
                     sequence of strings, then the map contains entries based on the supplied value.
                     Any string appearing in the option value that is non-zero-length and 
                     is not equal (using codepoint collation) to
                     any previous string results in an entry
                     pairing that string to its 1-based position in the sequence.
                  </p>
                     <p>The allocation of column numbers is <emph>not</emph> adjusted based on the 
                        <code>select-columns</code> 
                        option; the supplied list of names is expected to refer to columns
                        in the result, not to columns in the input.</p>
                  </item>
               </ulist>
         </fos:meaning>
      </fos:field>
      <fos:field name="rows" type="array(xs:string)*" required="true">
         <fos:meaning><p>This entry is a sequence of arrays of strings, holding the parsed
                  rows of the CSV data. The format is the same as the result of the
                  <function>fn:csv-to-arrays</function> function, except that the first row
                  is omitted in the case where the <code>header</code>
                  option is <code>true</code>. If there are no data rows in the CSV, the
                  value will be the empty sequence.</p></fos:meaning>
      </fos:field>
      <fos:field name="get" type="function(xs:positiveInteger, (xs:positiveInteger | xs:string)) as xs:string" required="true">
         <fos:meaning><p>A function providing ready access to a given field in a given
      row. The <code>get</code> function has signature:</p>
                     <eg>function($row as xs:positiveInteger, $column as (xs:positiveInteger | xs:string)) as xs:string</eg>
                     <p>The function takes two arguments: the first is an
                     integer giving the row number (1-based), the second
                     identifies a column either by its name or by its 1-based
                     position.</p>
         
         <p>Except in error cases (described below), 
                  the function call <code>$csv?get($R, $C)</code>, where <code>$C</code>
                  is an integer, returns the value of <code>$csv?rows[$R] => array:get($C, "")</code>,
                  and the function call <code>$csv?get($R, $K)</code>, where <code>$K</code>
                  is a string, returns the value of <code>$csv?get($R, $csv?column-index($K))</code>.</p>

               <p>The properties of the function are as follows:</p>
                  <glist>
                     <gitem>
                        <label>Name</label>
                        <def><p>Absent</p></def>
                     </gitem>
                     <gitem>
                        <label>Signature</label>
                        <def><p><code>(xs:positiveInteger, (xs:positiveInteger | xs:string)) => xs:string</code></p></def>
                     </gitem>
                     <gitem>
                        <label>Non-local variable bindings</label>
                        <def><p>None</p></def>
                     </gitem>
                     <gitem>
                        <label>Body</label>
                        <def><p>As described in the specification above</p></def>
                     </gitem>
                     <gitem>
                        <label>Errors</label>
                        <def><p>A dynamic error <errorref class="CV" code="0004"/> occurs if the
                           supplied <var>$key</var> is a string and does not occur in the map of column
                           names.</p></def>
                     </gitem>
                     <gitem>
                        <label>Rules</label>
                        <def>
                           <p>The function returns a field in the result.</p>
                           <p>The first argument <code>$row</code> selects a row within the sequence of rows
                              returned as <var>rows</var> by position (one-based). If the value is out of range for the number
                              of rows returned, the <code>get</code> function returns a zero-length
                              string.</p>
                           <p>The second argument <code>$col</code> may be either an integer or a string.</p>
                           <p>If <code>$col</code> is an integer then it selects a field within the
                              selected row by position (one-based). If the value is out of range for the number
                              of fields in the selected row, the <code>get</code> function returns a zero-length
                              string.</p>
                           <p>If <code>$col</code> is a string, the string is mapped to an integer using the
                              map in the returned <var>column-index</var>. If the string is not present
                              in this map, then an error is raised <errorref class="CV" code="0004"/>. The resulting
                              integer is then used as if it were supplied as <code>$col</code> directly.</p>

                        </def>
                     </gitem>
                  </glist>
         </fos:meaning>
      </fos:field>
   </fos:record-type>
   

   <!--<fos:record-type id="load-xquery-module-record" extensible="false">
      <fos:field name="variables" type="map(xs:QName, item()*)" required="true">
         <fos:meaning>
                  <p>This map (<var>V</var> ) contains one entry for each public
                  global variable declared in the library module. The key of the
                  entry is the name of the variable, as an <code>xs:QName</code>
                  value; the associated value is the value of the variable.</p>
         </fos:meaning>        
      </fos:field>
      <fos:field name="functions" type="map(xs:QName, map(xs:integer, function(*)))" required="true">
         <fos:meaning>
            <p>This map (<var>F</var> ) contains one entry for each distinct QName
            <var>Q</var> that represents the name of a public and non-external
            function declared in the library module. The key of the entry is
            <var>Q</var>, as an <code>xs:QName</code> value; the associated value
            is a map <var>A</var>. This map (<var>A</var>) contains one entry for
            each arity <var>N</var> within the arity range of any of the function
            declarations with the given name; its key is <var>N</var>, as an
            <code>xs:integer</code> value, and its associated value is a function
            item obtained as if by evaluating a named function reference
            <code>Q#N</code>, using the static and dynamic context of the call on
            <function>fn:load-xquery-module</function>. The function item can be invoked
            using the rules for dynamic function invocation.</p>
         </fos:meaning>         
      </fos:field>
   </fos:record-type>
   -->
   

   <fos:record-type id="random-number-generator-record" extensible="false">
      <fos:summary>
         <p>This record type is used to represent the result of a call on
         the <function>fn:random-number-generator</function> function.</p>
      </fos:summary>
      <fos:field name="number" type="xs:double" required="true">
         <fos:meaning><p>An <code>xs:double</code> greater than or equal
               to zero (0.0e0), and less than one (1.0e0).</p></fos:meaning>
      </fos:field>
      <fos:field name="next" type="fn() as random-number-generator-record" required="true">
         <fos:meaning>
               <p>A zero-arity function that can be called to return another random number
            generator.</p>
               <p>The properties of this function are as follows:</p>
               <ulist>
                  <item>
                     <p>name: absent</p>
                  </item>
                  <item>
                     <p>parameter names: ()</p>
                  </item>
                  <item>
                     <p>signature: <code>() => random-number-generator-record</code></p>
                  </item>
                  <item>
                     <p>non-local variable bindings: none</p>
                  </item>
                  <item>
                     <p>implementation: implementation-dependent</p>
                  </item>
               </ulist>
         </fos:meaning>
      </fos:field>
      <fos:field name="permute" type="function(item()*) as item()*" required="true">
         <fos:meaning>
               <p>A function with arity 1 (one), which takes an arbitrary sequence
            as its argument, and returns a random permutation of that sequence.</p>
               <p>The properties of this function are as follows:</p>
               <ulist>
                  <item>
                     <p>name: absent</p>
                  </item>
                  <item>
                     <p>parameter names: <code>"arg"</code></p>
                  </item>
                  <item>
                     <p>signature: <code>(item()*) => item()*</code></p>
                  </item>
                  <item>
                     <p>non-local variable bindings: none</p>
                  </item>
                  <item>
                     <p>body: implementation-dependent</p>
                  </item>
               </ulist>
         </fos:meaning>
      </fos:field>
   </fos:record-type>
   
 
   
   <fos:function name="node-name" prefix="fn">
      <fos:signatures>
         <fos:proto name="node-name" return-type="xs:QName?">
            <fos:arg name="node" type="node()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the name of a node, as an <code>xs:QName</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the empty sequence is returned.</p>
         <p>Otherwise, the function returns the result of the <code>dm:node-name</code> accessor as
            defined in <bibref
               ref="xpath-datamodel-31"/> (see <xspecref spec="DM40" ref="dm-node-name"/>).</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/>.</p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, 
                  type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>For element and attribute nodes, the name of the node is returned as an
               <code>xs:QName</code>, retaining the prefix, namespace URI, and local part.</p>
         <p>For processing instructions, the name of the node is returned as an
               <code>xs:QName</code> in which the prefix and namespace URI are <xtermref
               ref="dt-absent" spec="DM40">absent</xtermref>.</p>
         <p>For a namespace node, the function returns the empty sequence if the node represents the
            default namespace; otherwise it returns an <code>xs:QName</code> in which prefix and
            namespace URI are <xtermref
               ref="dt-absent" spec="DM40"
            >absent</xtermref> and the local
            part is the namespace prefix being bound.</p>
         <p>For all other kinds of node, the function returns the empty sequence.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="e" id="v-node-name-e"><![CDATA[<doc>
  <p id="alpha" xml:id="beta">One</p>
  <p id="gamma" xmlns="http://example.com/ns">Two</p>
  <ex:p id="delta" xmlns:ex="http://example.com/ns">Three</ex:p>
  <?pi 3.14159?>
</doc>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-node-name-e" spec="XQuery">
               <fos:expression>node-name($e//*[@id = 'alpha'])</fos:expression>
               <fos:result>QName("", "p")</fos:result>
            </fos:test>
            <fos:test use="v-node-name-e" spec="XQuery">
               <fos:expression>node-name($e//*[@id = 'gamma'])</fos:expression>
               <fos:result>QName("http://example.com/ns", "p")</fos:result>
            </fos:test>
            <fos:test use="v-node-name-e" spec="XQuery">
               <fos:expression>node-name($e//*[@id = 'delta'])</fos:expression>
               <fos:result>QName("http://example.com/ns", "ex:p")</fos:result>
            </fos:test>
            <fos:test use="v-node-name-e" spec="XQuery">
               <fos:expression>node-name($e//processing-instruction())</fos:expression>
               <fos:result>QName("", "pi")</fos:result>
            </fos:test>
            <fos:test use="v-node-name-e" spec="XQuery">
               <fos:expression>node-name($e//*[@id = 'alpha']/text())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test use="v-node-name-e" spec="XQuery">
               <fos:expression>node-name($e//*[@id = 'alpha']/@id)</fos:expression>
               <fos:result>QName("", "id")</fos:result>
            </fos:test>
            <fos:test use="v-node-name-e" spec="XQuery">
               <fos:expression>node-name($e//*[@id = 'alpha']/@xml:id)</fos:expression>
               <fos:result>#xml:id</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   
   <fos:function name="type-of" prefix="fn">
      <fos:signatures>
         <fos:proto name="type-of" return-type="xs:string">
            <fos:arg name="value" type="item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns information about the type of a value, as a string.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a string, whose lexical form will always match
            the grammar of <xnt spec="XP40" ref="SequenceType">SequenceType</xnt>, representing a sequence type that matches
         <code>$value</code>.</p>
         <p>If <code>$value</code> is the empty sequence, the function returns the string <code>"empty-sequence()"</code>.</p>
         <p>Otherwise, the returned string is the concatenation of:</p>
         <olist>
            <item><p>A string representing the distinct item types that are present in <code>$value</code>,
               formed as follows:</p>
               <olist>
                  <item><p>For each item in <code>$value</code>, construct a string representing its item type
                  as described below.</p></item>
                  <item><p>Eliminate duplicate strings from this list by applying the <function>fn:distinct-values</function>
                  function, forming a sequence of strings <var>$ss</var>.</p></item>
                  <item><p>If <var>$ss</var> contains only one string, use that string.</p></item>
                  <item><p>Otherwise, return the result of the expression <code>`({ fn:string-join(<var>$ss</var>, "|") })`</code>.</p></item>
               </olist>
            </item>
            <item><p>An occurrence indicator: absent if <code>$value</code> contains exactly one item, or
            <code>"+"</code> if it contains more than one item.</p></item>
         </olist>
         <p>The string representing the type of an individual item <var>J</var> is constructed as follows:</p>
         <olist>
            <item><p>If <var>J</var> is an <xtermref spec="DM40" ref="dt-XNode"/>, the result is one of the following
            strings, determined by the node kind of the node (see <xspecref spec="DM40" ref="dm-node-kind"/>):</p>
            <p><slist>
               <sitem><code>"document-node()"</code></sitem>
               <sitem><code>"element()"</code></sitem>
               <sitem><code>"attribute()"</code></sitem>
               <sitem><code>"text()"</code></sitem>
               <sitem><code>"processing-instruction()"</code></sitem>
               <sitem><code>"comment()"</code></sitem>
               <sitem><code>"namespace-node()"</code></sitem>
            </slist></p>
            </item>
            <item><p>If <var>J</var> is a <xtermref spec="DM40" ref="dt-JNode"/>, the result is the string <code>"jnode()"</code>.</p>
            </item>
            <item>
               <p>If <var>J</var> is an atomic item, the result is a string chosen as follows:</p>
               <olist>
                  <item><p>Let <var>T</var> be the type denoted by the type annotation of <var>J</var>.</p></item>
                  <item><p>If <var>T</var> is an anonymous type, set <var>T</var> to the base type of <var>T</var>, and
                  repeat until a type is reached that is not anonymous.</p></item>
                  <item><p>If the name of <var>T</var> is in the namespace <code>http://www.w3.org/2001/XMLSchema</code>,
                  return the string <code>"xs:<var>local</var>"</code> where <var>local</var> is the local part of the
                  name of <var>T</var>.</p></item>
                  <item><p>Otherwise, return the name of <var>T</var> in the form of a 
                     <xnt spec="XP40" ref="URIQualifiedName">URIQualifiedName</xnt> (that is, <code>"Q{<var>uri</var>}<var>local</var>"</code>,
                     or <code>"Q{}<var>local</var>"</code> if the name is in no namespace).</p></item>
               </olist>
            </item>
            <item><p>If <var>J</var> is a function item:</p>
               <olist>
                 <item><p>If <var>J</var> is an array, return <code>"array(*)"</code>.</p></item>
                 <item><p>If <var>J</var> is a map, return <code>"map(*)"</code>.</p></item>
                 <item><p>Otherwise, return <code>"fn(*)"</code>.</p></item>
               </olist>
            </item>
         </olist>
      </fos:rules>
 
      <fos:errors>
         <p>If the <code>$value</code> argument is omitted and the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>, the function raises
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/>.</p>

      </fos:errors>
      <fos:notes>
         <p>In general, an item matches more than one type, and there are cases where there is no single matching type that
         is more specific than all the others. This is especially true with functions, maps, and arrays. This function therefore
         selects one of the types that matches the item, which is not necessarily the most specific type.</p>
         
         <p>This function should not be used as a substitute for an <code>instance of</code> test. The precise type annotation
         of the result of an expression is not always predictable, because processors are free to deliver a more specific type
         than is mandated by the specification. For example, if <code>$n</code> is of type <code>xs:positiveInteger</code>,
         then the result of <code>abs($n)</code> is guaranteed to be an instance of <code>xs:integer</code>, but an 
         implementation might reasonably return the supplied value unchanged: that is, a value whose actual type 
         annotation is <code>xs:positiveInteger</code>. Similarly the type annotation of the value returned by
         <code>position()</code> might be <code>xs:long</code> rather than <code>xs:integer</code>.</p>
         
         <p>Implementations <rfc2119>should</rfc2119>, however, refrain from exposing types that are purely internal.
         For example, an implementation might have an optimized internal representation for strings consisting entirely
         of ASCII characters, or for single-character strings; if this is the case then the type annotation returned by this function
         should be a user-visible supertype such as <code>xs:string</code>.</p>
      </fos:notes>
 
      <fos:examples>
         <fos:variable name="e" id="v-type-of-e"><![CDATA[<doc>
  <p id="alpha" xml:id="beta">One</p>
  <p id="gamma" xmlns="http://example.com/ns">Two</p>
  <ex:p id="delta" xmlns:ex="http://example.com/ns">Three</ex:p>
  <?pi 3.14159?>
</doc>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-type-of-e" spec="XQuery">
               <fos:expression>type-of($e//*[@id = 'alpha'])</fos:expression>
               <fos:result>"element()"</fos:result>
            </fos:test>
            <fos:test use="v-type-of-e" spec="XQuery">
               <fos:expression>type-of($e//*)</fos:expression>
               <fos:result>"element()+"</fos:result>
            </fos:test>
            <fos:test use="v-type-of-e" spec="XQuery">
               <fos:expression>type-of($e//@id[. = 'gamma'])</fos:expression>
               <fos:result>"attribute()"</fos:result>
            </fos:test>
            <fos:test use="v-type-of-e" spec="XQuery">
               <fos:expression>type-of($e//node()[. = '3.14159'])</fos:expression>
               <fos:result>"processing-instruction()"</fos:result>
            </fos:test>
            <fos:test use="v-type-of-e" spec="XQuery">
               <fos:expression>type-of($e//no-such-node)</fos:expression>
               <fos:result>"empty-sequence()"</fos:result>
            </fos:test>
            <fos:test use="v-type-of-e" spec="XQuery">
               <fos:expression>type-of($e/child::node())</fos:expression>
               <fos:result>"(element()|processing-instruction())+"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>type-of(1)</fos:expression>
               <fos:result>"xs:integer"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>type-of(1 to 5)</fos:expression>
               <fos:result>"xs:integer+"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>type-of((1, 1.2, 2))</fos:expression>
               <fos:result>"(xs:integer|xs:decimal)+"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>type-of([ 1, 2, 3 ])</fos:expression>
               <fos:result>"array(*)"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>type-of({ 'a': 1 })</fos:expression>
               <fos:result>"map(*)"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>type-of(type-of#1)</fos:expression>
               <fos:result>"fn(*)"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>type-of(jtree([]))</fos:expression>
               <fos:result>"jnode(array(*))"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1550" PR="1570" date="2024-11-12"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="nilled" prefix="fn">
      <fos:signatures>
         <fos:proto name="nilled" return-type="xs:boolean?">
            <fos:arg name="node" type="node()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>

      <fos:summary>
         <p>Returns <code>true</code> for an element that is <term>nilled</term>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the function returns the result of the <code>dm:nilled</code> accessor as
            defined in <bibref
               ref="xpath-datamodel-31"/> (see <xspecref spec="DM40" ref="dm-nilled"/>).</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>If <code>$node</code> is not an element node, the function returns the empty
            sequence.</p>
         <p>If <code>$node</code> is an untyped element node, the function returns <code>false</code>.</p>
         <p>In practice, the function returns <code>true</code> only for an element node that has
            the attribute <code>xsi:nil="true"</code> and that is successfully validated against a
            schema that defines the element to be nillable; the detailed rules, however, are defined
            in <bibref
               ref="xpath-datamodel-31"/>.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="string" prefix="fn">
      <fos:signatures>
         <fos:proto name="string" return-type="xs:string">
            <fos:arg name="value" type="item()?" default="." usage="absorption"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value of <code>$value</code> represented as an <code>xs:string</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the zero-length
            string.</p>

         <p>If <code>$value</code> is an <xtermref spec="DM40" ref="dt-XNode"/>, 
            the function returns the string value of the node, as obtained using the
                     <code>dm:string-value</code> accessor defined in <bibref
               ref="xpath-datamodel-31"/> (see <xspecref spec="DM40" ref="dm-string-value"/>).</p>
         
         <p>If <code>$value</code> is a <xtermref spec="DM40" ref="dt-JNode"/>, 
            the function returns the result of <code>string(jvalue($value))</code>.
         This will fail in the case where <code>jvalue($value)</code> is a map or an array.</p>

         <p>If <code>$value</code> is an atomic item, the function returns the result of the expression <code>$value cast
                     as xs:string</code> (see <specref
               ref="casting"/>).</p>

         <p>In all other cases, a dynamic error occurs (see below).</p>


      </fos:rules>
      <fos:errors>

         <p>The following errors may be raised when <code>$value</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="dynamic"/>.</p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>item()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>
         <p>A type error is raised <errorref class="TY" code="0014" type="type"
               /> if
               <code>$value</code> is a function item (this includes maps and arrays).</p>
      </fos:errors>
      <fos:notes>
         <p>Every node has a string value, even an element with element-only
            content (which has no typed value). Moreover, casting an atomic item to a string always
            succeeds. Functions, maps, and arrays have no string value, so these 
            satisfy the type signature but cause failure. Applying the <function>string</function>
            function to a JNode succeeds if the JNode wraps a simple value such as a string, number,
         or boolean, or if it wraps an XNode, but it fails in the case where the JNode wraps a map
         or an array.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>string(23)</fos:expression>
               <fos:result>"23"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>string(false())</fos:expression>
               <fos:result>"false"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>string("Paris")</fos:expression>
               <fos:result>"Paris"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>string((1, 2, 3))</fos:expression>
               <fos:error-result error-code="XPTY0004"/>
            </fos:test>
            <fos:test>
               <fos:expression>string([ [ 1, 2 ], [ 3, 4 ] ])</fos:expression>
               <fos:error-result error-code="FOTY0014"/>
            </fos:test>
            <fos:test>
               <fos:expression>string(abs#1)</fos:expression>
               <fos:error-result error-code="FOTY0014"/>
            </fos:test>
            <fos:test>
               <fos:expression>string({ "x": [10, 20, 30] }/x/*[3])</fos:expression>
               <fos:result>"30"</fos:result>
            </fos:test>
         </fos:example>
         <fos:variable id="v-string-para" name="para"
            ><![CDATA[<para>There lived a <term author="Tolkien">hobbit</term>.</para>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-string-para" spec="XQuery">
               <fos:expression>string($para)</fos:expression>
               <fos:result>"There lived a hobbit."</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="data" prefix="fn">
      <fos:signatures>
         <fos:proto name="data" return-type="xs:anyAtomicType*">
            <fos:arg name="input" type="item()*" default="." usage="absorption"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the result of atomizing a sequence. This process flattens arrays, and replaces
            nodes by their typed values.</p>
      </fos:summary>
      <fos:rules>
         <p> The result of <function>fn:data</function> is the sequence of atomic items produced by
            applying the following rules to each item in <code>$input</code>:</p>
         <ulist>
            <item>
               <p>If the item is an atomic item, it is appended to the result sequence.</p>
            </item>
            <item>
               <p>If the item is an <xtermref spec="DM40" ref="dt-XNode"/>, 
                  the typed value of the node is appended to the result
                  sequence. The typed value is a sequence of zero or more atomic items:
                  specifically, the result of the <code>dm:typed-value</code> accessor as defined in
                     <bibref
                     ref="xpath-datamodel-31"/> (See <xspecref spec="DM40" ref="dm-typed-value"
                  />).</p>
            </item>
            <item>
               <p>If the item is a <xtermref spec="DM40" ref="dt-JNode"/>,
               the atomized value of its <term>·jvalue·</term> property is appended to
               the result sequence.</p>
            </item>
            <item>
               <p>If the item is an array, the result of applying <function>fn:data</function> to
                  each member of the array, in order, is appended to the result sequence.</p>
            </item>
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <errorref class="TY" code="0012" type="type"
               /> if an item in the
            sequence <code>$input</code> is a node that does not have a typed value. </p>
         <p>A type error is raised <errorref class="TY" code="0013" type="dynamic"
               /> if an item in
            the sequence <code>$input</code> is a function item other than
               an array. </p>
         <p>A type error is raised <xerrorref spec="XP" class="DY" code="0002" type="type"/>
            if <code>$input</code> is omitted and the context value is
               <xtermref ref="dt-absent" spec="DM40">absent</xtermref>.</p>
      </fos:errors>
      <fos:notes>
         <p>The process of applying the <function>fn:data</function> function to a sequence is referred to
            as <term>atomization</term>. In many cases an explicit call on <function>fn:data</function> is
            not required, because atomization is invoked implicitly when a node or sequence of nodes
            is supplied in a context where an atomic item or sequence of atomic items is
            required.</p>
         <p>The result of atomizing the empty sequence is the empty sequence.</p>
         <p>The result of atomizing the empty array is the empty sequence.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>data(123)</fos:expression>
               <fos:result>123</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>data((123, 456))</fos:expression>
               <fos:result>123, 456</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>data([ [ 1, 2 ], [ 3, 4 ] ])</fos:expression>
               <fos:result>1, 2, 3, 4</fos:result>
            </fos:test>
         </fos:example>

         <fos:variable id="v-data-para" name="para"
            ><![CDATA[<para>There lived a <term author="Tolkien">hobbit</term>.</para>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-data-para" spec="XQuery">
               <fos:expression>data($para)</fos:expression>
               <fos:result>xs:untypedAtomic("There lived a hobbit.")</fos:result>
            </fos:test>
            <fos:test use="v-data-para" spec="XQuery">
               <fos:expression>data($para/term/@author)</fos:expression>
               <fos:result>xs:untypedAtomic("Tolkien")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>data(abs#1)</fos:expression>
               <fos:error-result error-code="FOTY0013"/>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="base-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="base-uri" return-type="xs:anyURI?">
            <fos:arg name="node" type="node()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the base URI of a node.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the function returns the empty
            sequence.</p>
         <p>Otherwise, the function returns the value of the <code>dm:base-uri</code> accessor
            applied to the node <code>$node</code>. This accessor is defined, for each kind of
            node, in the XDM specification (See <xspecref spec="DM40" ref="dm-base-uri"/>).</p>
         <note><p>As explained in XDM, document, element and processing-instruction nodes have a
            base-uri property which may be empty. The base-uri property for all other node kinds is
            the empty sequence. The dm:base-uri accessor returns the base-uri property of a node if
            it exists and is non-empty; otherwise it returns the result of applying the dm:base-uri
            accessor to its parent, recursively. If the node does not have a parent, or if the
            recursive ascent up the ancestor chain encounters a parentless node whose base-uri
            property is empty, the empty sequence is returned. In the case of namespace nodes,
            however, the result is always the empty sequence &#x2014; it does not depend on the base URI of
            the parent element.</p></note>


         <p>See also <function>fn:static-base-uri</function>.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>
         <p>A dynamic error <rfc2119>may</rfc2119> be raised <errorref class="RG" code="0002"/>
            if the base URI is not a valid Legacy Extended IRI reference (see <bibref ref="LEIRI"/>). </p>
      </fos:errors>
      <fos:changes>
         <fos:change issue="2148" PR="2223" date="2025-10-02">
            <p>An error may now be raised if the base URI is not a valid LEIRI reference.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="document-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="document-uri" return-type="xs:anyURI?">
            <fos:arg name="node" type="node()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the URI of a resource where a document can be found, if available.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>If <code>$node</code> is not a document node, the function returns the empty
            sequence.</p>
         <p>Otherwise, the function returns the value of the <code>document-uri</code> accessor
            applied to <code>$node</code>, as defined in <bibref
               ref="xpath-datamodel-31"/> (See
               <xspecref spec="DM40"
               ref="DocumentNodeAccessors"/>).</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>In the 3.1 version of this specification, it was mandated that two distinct documents could
         not have the same document-uri property: more specifically, it was guaranteed that for any document node
         <code>$D</code>, either <code>document-uri($D)</code> would be absent, or <code>doc(document-uri($D))</code>
         would return <code>$D</code>.</p>
         
         <p>For various reasons, this constraint has proved impractical. Different parts of an application
            may read the same external resource in different ways, for example with or without validation or
            whitespace stripping, leading to different document nodes derived from the same external
            resource having the same <code>document-uri</code> property. In addition, the specification
            explicitly allows implementations, at user request, to relax the requirements for determinism 
            of resource access functions, which makes it possible for multiple calls of functions such as
            <function>fn:doc</function>, <function>fn:json-doc</function>, or <function>fn:collection</function> to return
            different results for the same supplied URI.</p>
        
         <p>Although the uniqueness of the <code>document-uri</code> property is no longer
            an absolute constraint, it is still desirable that implementations should where possible
            respect the principle that URIs are usable as identifiers for resources.</p>
         
         <p diff="chg" at="issue898">In the case of a document node <code>$D</code> returned by the <function>fn:doc</function>
            function, it will generally be the case that <code>fn:document-uri($D)</code> returns a URI <code>$U</code>
            such that a call on <code>fn:doc($U)</code> in the same dynamic context will return the same document
            node <code>$D</code>. The URI <code>$U</code> will not necessarily be the same URI that was originally
            passed to the <function>fn:doc</function> function, since several URIs may identify the same resource.</p>
         

         <p diff="chg" at="issue898">It is <rfc2119>recommended</rfc2119> that implementations of <function>fn:collection</function>
            should ensure that any documents included in the returned collection, if they have a non-empty
            <function>fn:document-uri</function> property, should be such that a call on <function>fn:doc</function> supplying this URI
            returns the same document node.</p>
         
         
         
      </fos:notes>
      <fos:changes>
         <fos:change issue="898 1161" PR="1265" date="2024-07-02">
            <p>The constraints on the result of the function have been relaxed.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="error" prefix="fn">
      <fos:signatures>
         <fos:proto name="error" return-type="item()*">
            <fos:arg name="code" type="xs:QName?" default="()"/>
            <fos:arg name="description" type="xs:string?" default="()"/>
            <fos:arg name="value" type="item()*" default="." usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Calling the <function>fn:error</function> function raises an application-defined error.</p>
      </fos:summary>
      <fos:rules>
         <p>This function never returns a value. Instead it always raises an error. The effect of
            the error is identical to the effect of dynamic errors raised implicitly, for example
            when an incorrect argument is supplied to a function.</p>
         <p>The parameters to the <function>fn:error</function> function supply information that is
            associated with the error condition and that is made available to a caller that asks for
            information about the error. The error may be caught either by the host language (using
            a try/catch construct in XSLT or XQuery, for example), or by the calling application or
            external processing environment. The way in which error information is returned to the
            external processing environment is <termref
               def="implementation-dependent">implementation-dependent</termref>.</p>

         <p>There are three pieces of information that may be associated with an error.</p>
         <ulist>
            <item>
               <p>The <code>$code</code> is an error code that distinguishes this error from others.
                  It is an <code>xs:QName</code>; the namespace URI conventionally identifies the
                  component, subsystem, or authority responsible for defining the meaning of the
                  error code, while the local part identifies the specific error condition. The
                  namespace URI <code>http://www.w3.org/2005/xqt-errors</code> is used for errors
                  defined in this specification; other namespace URIs may be used for errors defined
                  by the application.</p>
               <p>If the external processing environment expects the error code to be returned as a
                  URI or a string rather than as an <code>xs:QName</code>, then an error code with
                  namespace URI <code>NS</code> and local part <code>LP</code> will be returned in
                  the form <code>NS#LP</code>. The namespace URI part of the error code should
                  therefore not include a fragment identifier.</p>
               <p>If <code>$code</code> is the empty sequence, the effective value of the error code
                  is <code>fn:QName('http://www.w3.org/2005/xqt-errors', 'err:FOER0000')</code>.</p>
            </item>
            <item>
               <p>The <code>$description</code> is a natural-language description of the error
                  condition.</p>
               <p>If the value is the empty sequence, then the effective value of the description is
                  <termref def="implementation-dependent">implementation-dependent</termref>.</p>
            </item>
            <item>
               <p>The <code>$value</code> is an arbitrary value used to convey additional
                  information about the error, and may be used in any way the application
                  chooses.</p>
               <p>If the value supplied is the empty sequence, then the effective value of the
                  error object is
                  <termref def="implementation-dependent">implementation-dependent</termref>.</p>
            </item>
         </ulist>



      </fos:rules>
      <fos:errors>
         <p>This function always raises a dynamic error. By default, it raises <errorref class="ER"
               code="0000"/></p>
      </fos:errors>
      <fos:notes>
         <p>The value of the <code>$description</code> parameter may need to be localized.</p>
         <p>Since the function never returns a value, the declared return type of <code>item()*</code>
            is a convenient fiction. It is relevant insofar as a function item such as <code>error#1</code>
            may (as a consequence of function coercion) be supplied in contexts where a function with a more specific
            return type is required.</p>
         <p>Any QName may be used as an error code; there are no reserved names or namespaces. The
            error is always classified as a dynamic error, even if the error code used is one that
            is normally used for static errors or type errors.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>error()</fos:expression>
               <fos:error-result error-code="FOER0000"/>
               <fos:postamble>This returns the URI
                     <code>http://www.w3.org/2005/xqt-errors#FOER0000</code> (or the corresponding
                     <code>xs:QName</code>) to the external processing environment, unless the error
                  is caught using a try/catch construct in the host language.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>error(
  QName('http://www.example.com/HR', 'myerr:toohighsal'),
  'Salary is too high'
)</eg></fos:expression>
               <fos:error-result error-code="myerr:toohighsal"/>
               <fos:postamble>This returns <code>http://www.example.com/HR#toohighsal</code> and the
                     <code>xs:string</code>
                  <code>"Salary is too high"</code> (or the corresponding
                     <code>xs:QName</code>) to the external processing environment, unless the error
                  is caught using a try/catch construct in the host language.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>All three arguments are now optional, and each argument can be set
            to the empty sequence. Previously if <code>$description</code> was supplied, it could not be empty.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="trace" prefix="fn">
      <fos:signatures>
         <fos:proto name="trace" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="label" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Provides an execution trace intended to be used in debugging queries.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>$input</code>, unchanged.</p>
         <p>In addition, the values of <code>$input</code>, typically serialized and converted
            to an <code>xs:string</code>, and <code>$label</code> (if non-empty) <rfc2119>may</rfc2119>
            be output to an <termref def="implementation-defined"/> destination.</p>
         <p>Any serialization of the implementation’s trace output <rfc2119>must not</rfc2119> raise an error.
            This can be achieved (for example) by using a serialization method that can handle
            arbitrary input, such as the adaptive output method (see
            <xspecref spec="SER31" ref="adaptive-output"/>).</p>
         <p>The format of the trace output and its order are
            <termref def="implementation-dependent"/>. Therefore, the order in which the output
            appears is not predictable. This also means that if dynamic errors occur
            (whether or not they are caught using try/catch), it may be unpredictable whether
            any output is reported before the error occurs.</p>
      </fos:rules>
      <fos:notes>
         <p>If the trace information is unrelated to a specific value,
            <function>fn:message</function> can be used instead.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $v := 124.84
return fn:trace($v, 'the value of $v is: ')</eg></fos:expression>
               <fos:result narrative="true">The function returns the <code>xs:decimal</code> value <code>124.84</code>,
               while outputting a message such as "the value of $v is: 124.84" to 
               an <termref def="implementation-defined"/> destination. The format of the message
               is also <termref def="implementation-defined"/>.</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>//book[xs:decimal(@price) gt 100] 
    => trace('books more expensive than €100:')</eg></fos:expression>
               <fos:result narrative="true">The result of the expression is the same as the result of
               <code>//book[xs:decimal(@price) gt 100]</code>, but evaluation has the side-effect of
               providing diagnostic feedback to the user.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
            
            
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The <code>$label</code> argument can now be set
            to the empty sequence. Previously if <code>$label</code> was supplied, it could not be empty.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="message" prefix="fn">
      <fos:signatures>
         <fos:proto name="message" return-type="empty-sequence()">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="label" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Outputs trace information and discards the result.</p>
      </fos:summary>
      <fos:rules>
         <p>Similar to <function>fn:trace</function>, the values of <code>$input</code>,
            typically serialized and converted to an <code>xs:string</code>, and <code>$label</code>
            (if non-empty) <rfc2119>may</rfc2119> be output to an
            <termref def="implementation-defined"/> destination.</p>
         <p>In contrast to <function>fn:trace</function>, the function returns the empty sequence.</p>
         <p>Any serialization of the implementation’s log output <rfc2119>must not</rfc2119> raise an error.
            This can e.g. be achieved by using a serialization method that can handle arbitrary
            input, such as the <xspecref spec="SER31" ref="adaptive-output"/>.</p>
         <p>The format of the log output and its order are
            <termref def="implementation-dependent"/>. Therefore, the order in which the output
            appears is not predictable. This also means that if dynamic errors occur
            (whether or not they are caught using try/catch), it may be unpredictable whether
            any output is logged before the error occurs.</p>
      </fos:rules>
      <fos:notes>
         <p>The function can be used for debugging. It can also be helpful in productive
            environments, e.g. to store dynamic input and evaluations to log files.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>//book[if (xs:decimal(@price) lt 1000) 
                     then true() 
                     else message(@price, @title || ' is unexpectedly expensive: ')]</eg></fos:expression>
               <fos:result narrative="true">The result of the expression is the same as the result of
               <code>//book[xs:decimal(@price) lt 1000]</code>, but evaluation has the side-effect of
               providing diagnostic feedback to the user relating to books above this price threshold.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
            
            
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="574 651" PR="629 803" date="2023-11-07"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="numeric-add" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-add" return-type="xs:numeric">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="numeric"
         >Defines the semantics of the <code>+</code> operator when
         applied to two numeric values</fos:opermap>
      <fos:summary>
         <p>Returns the arithmetic sum of its operands: (<code>$arg1 + $arg2</code>).</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>
      </fos:rules>
      <fos:notes>
         <p> For <code>xs:float</code> or <code>xs:double</code> values, if one of the operands is a
            zero or a finite number and the other is <code>INF</code> or <code>-INF</code>,
               <code>INF</code> or <code>-INF</code> is returned. If both operands are
               <code>INF</code>, <code>INF</code> is returned. If both operands are
               <code>-INF</code>, <code>-INF</code> is returned. If one of the operands is
               <code>INF</code> and the other is <code>-INF</code>, <code>NaN</code> is
            returned.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="numeric-subtract" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-subtract" return-type="xs:numeric">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="numeric"
         >Defines the semantics of the <code>-</code> operator when
         applied to two numeric values. </fos:opermap>
      <fos:summary>
         <p>Returns the arithmetic difference of its operands: (<code>$arg1 - $arg2</code>).</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>
      </fos:rules>
      <fos:notes>
         <p> For <code>xs:float</code> or <code>xs:double</code> values, if one of the operands is a
            zero or a finite number and the other is <code>INF</code> or <code>-INF</code>, an
            infinity of the appropriate sign is returned. If both operands are <code>INF</code> or
               <code>-INF</code>, <code>NaN</code> is returned. If one of the operands is
               <code>INF</code> and the other is <code>-INF</code>, an infinity of the appropriate
            sign is returned.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="numeric-multiply" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-multiply" return-type="xs:numeric">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="*" types="numeric"
         >Defines the semantics of the <code>*</code> operator when
         applied to two numeric values.</fos:opermap>
      <fos:summary>
         <p>Returns the arithmetic product of its operands: (<code>$arg1 * $arg2</code>).</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>
      </fos:rules>
      <fos:notes>
         <p> For <code>xs:float</code> or <code>xs:double</code> values, if one of the operands is a
            zero and the other is an infinity, <code>NaN</code> is returned. If one of the operands
            is a non-zero number and the other is an infinity, an infinity with the appropriate sign
            is returned.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="numeric-divide" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-divide" return-type="xs:numeric">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="div" types="numeric"
         >Defines the semantics of the <code>div</code> operator when
         applied to two numeric values.</fos:opermap>
      <fos:summary>
         <p>Returns the arithmetic quotient of its operands: (<code>$arg1 div $arg2</code>).</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>
         <p>As a special case, if the types of both <code>$arg1</code> and <code>$arg2</code> are
               <code>xs:integer</code>, then the return type is <code>xs:decimal</code>.</p>

      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="AR" code="0001"
               /> for <code>xs:decimal</code>
            and <code>xs:integer</code> operands, if the divisor is (positive or negative) zero.</p>
      </fos:errors>
      <fos:notes>
         <p>For <code>xs:float</code> and <code>xs:double</code> operands, floating point division
            is performed as specified in <bibref
               ref="ieee754-2019"
               />. A positive number divided by
            positive zero returns <code>INF</code>. A negative number divided by positive zero
            returns <code>-INF</code>. Division by negative zero returns <code>-INF</code> and
               <code>INF</code>, respectively. Positive or negative zero divided by positive or
            negative zero returns <code>NaN</code>. Also, <code>INF</code> or <code>-INF</code>
            divided by <code>INF</code> or <code>-INF</code> returns <code>NaN</code>.</p>
      </fos:notes>

   </fos:function>
   <fos:function name="numeric-integer-divide" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-integer-divide" return-type="xs:integer">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="idiv" types="numeric"
         >Defines the semantics of the <code>idiv</code> operator when
         applied to two numeric values.</fos:opermap>
      <fos:summary>
         <p>Performs an integer division.</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>

         <p>If <code>$arg2</code> is <code>INF</code> or <code>-INF</code>, and <code>$arg1</code>
            is not <code>INF</code> or <code>-INF</code>, then the result is zero.</p>

         <p>Otherwise, subject to limits of precision and overflow/underflow conditions, the result
            is the largest (furthest from zero) <code>xs:integer</code> value <code>$N</code> such
            that the following expression is <code>true</code>:</p>

         <eg>abs($N * $arg2) le abs($arg1) and
compare($N * $arg2, 0) eq compare($arg1, 0).</eg>
         <note>
            <p>The second term in this condition ensures that the result has the correct sign.</p>
         </note>
         <p>The implementation may adopt a different algorithm provided that it is equivalent to
            this formulation in all cases where <termref
               def="implementation-dependent">implementation-dependent</termref> or <termref
               def="implementation-defined"
               >implementation-defined</termref> behavior does not affect the outcome, for example,
            the implementation-defined precision of the result of <code>xs:decimal</code>
            division.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="AR" code="0001"
            /> if the divisor is (positive
            or negative) zero.</p>
         <p>A dynamic error is raised <errorref class="AR" code="0002"
               /> if either operand is
               <code>NaN</code> or if <code>$arg1</code> is <code>INF</code> or
            <code>-INF</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>Except in situations involving errors, loss of precision, or overflow/underflow, the
            result of <code>$a idiv $b</code> is the same as <code>($a div $b) cast as
               xs:integer</code>.</p>
         <p>The semantics of this function are different from integer division as defined in
            programming languages such as Java and C++.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(10, 3)</fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(3, -2)</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(-3, 2)</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(-3, -2)</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(9.0, 3)</fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(-3.5, 3)</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(3.0, 4)</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(3.1E1, 6)</fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-integer-divide(3.1E1, 7)</fos:expression>
               <fos:result>4</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="numeric-mod" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-mod" return-type="xs:numeric">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="mod" types="numeric"
         >Defines the semantics of the <code>mod</code> operator when
         applied to two numeric values.</fos:opermap>
      <fos:summary>
         <p>Returns the remainder resulting from dividing <code>$arg1</code>, the dividend, by
               <code>$arg2</code>, the divisor. </p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>
         <p>The operation <code>a mod b</code> for operands that are <code>xs:integer</code> or
               <code>xs:decimal</code>, or types derived from them, produces a result such that
               <code>(a idiv b) * b + (a mod b)</code> is equal to <code>a</code> and the magnitude of
            the result is always less than the magnitude of <code>b</code>. This identity holds even
            in the special case that the dividend is the negative integer of largest possible
            magnitude for its type and the divisor is -1 (the remainder is 0). It follows from this
            rule that the sign of the result is the sign of the dividend.</p>

         <p> For <code>xs:float</code> and <code>xs:double</code> operands the following rules
            apply:</p>
         <ulist>
            <item>
               <p>If either operand is <code>NaN</code>, the result is <code>NaN</code>.</p>
            </item>
            <item>
               <p>If the dividend is positive or negative infinity, or the divisor is positive or
                  negative zero (0), or both, the result is <code>NaN</code>.</p>
            </item>
            <item>
               <p>If the dividend is finite and the divisor is an infinity, the result equals the
                  dividend.</p>
            </item>
            <item>
               <p>If the dividend is positive or negative zero and the divisor is finite, the result
                  is the same as the dividend.</p>
            </item>
            <item>
               <p>In the remaining cases, where neither positive or negative infinity, nor positive
                  or negative zero, nor <code>NaN</code> is involved, the result obeys <code>(a idiv
                     b)*b+(a mod b)</code> = <code>a</code>.
                  <!--float or double remainder r from a dividend n and a divisor d is defined by the mathematical relation r = n-(d * q) where q is an integer that is negative only if n/d is negative and positive only if n/d is positive, and whose magnitude is as large as possible without exceeding the magnitude of the true mathematical quotient of n and d.  -->
                  Division is truncating division, analogous to integer division, not <bibref
                     ref="ieee754-2019"
                  /> rounding division i.e. additional digits are truncated,
                  not rounded to the required precision.</p>
            </item>
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="AR" code="0001"
               /> for <code>xs:integer</code>
            and <code>xs:decimal</code> operands, if <code>$arg2</code> is zero.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-mod(10, 3)</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-mod(6, -2)</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-mod(4.5, 1.2)</fos:expression>
               <fos:result>0.9</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>op:numeric-mod(1.23E2, 0.6E1)</fos:expression>
               <fos:result>3.0E0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="numeric-unary-plus" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-unary-plus" return-type="xs:numeric">
            <fos:arg name="arg" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="numeric"
         >Defines the semantics of the unary <code>+</code> operator
         applied to a numeric value.</fos:opermap>
      <fos:summary>
         <p>Returns its operand with the sign unchanged: (<code>+ $arg</code>).</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>
         <p>The returned value is equal to <code>$arg</code>, and is an instance of
               <code>xs:integer</code>, <code>xs:decimal</code>, <code>xs:double</code>, or
               <code>xs:float</code> depending on the type of <code>$arg</code>.</p>
      </fos:rules>
      <fos:notes>
         <p>Because coercion rules are applied in the normal way, the unary
               <code>+</code> operator can be used to force conversion of an untyped node to a
            number: the result of <code>+@price</code> is the same as <code>xs:double(@price)</code>
            if the type of <code>@price</code> is <code>xs:untypedAtomic</code>.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="numeric-unary-minus" prefix="op">
      <fos:signatures>
         <fos:proto name="numeric-unary-minus" return-type="xs:numeric">
            <fos:arg name="arg" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="numeric"
         >Defines the semantics of the unary <code>-</code> operator when
         applied to a numeric value.</fos:opermap>
      <fos:summary>
         <p>Returns its operand with the sign reversed: <code>-$arg</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="op.numeric"/>.</p>
         <p>The returned value is an instance of <code>xs:integer</code>, <code>xs:decimal</code>,
               <code>xs:double</code>, or <code>xs:float</code> depending on the type of
               <code>$arg</code>.</p>
         <p>For <code>xs:integer</code> and <code>xs:decimal</code> arguments, <code>0</code> and
               <code>0.0</code> return <code>0</code> and <code>0.0</code>, respectively. For
               <code>xs:float</code> and <code>xs:double</code> arguments, <code>NaN</code> returns
               <code>NaN</code>, <code>0.0E0</code> returns <code>-0.0E0</code> and vice versa.
               <code>INF</code> returns <code>-INF</code>. <code>-INF</code> returns
               <code>INF</code>.</p>
      </fos:rules>
   </fos:function>
   <!--<fos:function name="numeric-equal" prefix="op" diff="chg" at="A">
      <fos:signatures>
         <fos:proto name="numeric-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="numeric" other-operators="ne le ge"
         >Defines the semantics of
         the <code>eq</code> operator when applied to two numeric values, and is also used in defining the
         semantics of <code>ne</code>, <code>le</code> and <code>ge</code>.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if and only if the value of <code>$arg1</code> is numerically equal to the value of
               <code>$arg2</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If either operand is the <code>xs:double</code> or <code>xs:float</code> value
         <code>NaN</code>, the result is false.</p>
         <p>In all other cases the result is true if and only if <code>fn:compare($arg1, $arg2)</code>
         returns zero.</p>
         <!-\-<p>General rules: see <specref ref="op.numeric"/> and <specref ref="comp.numeric"/>.</p>-\->
      </fos:rules>
      <fos:notes>
         <p>For <code>xs:float</code> and <code>xs:double</code> values, positive zero and negative
            zero compare equal. <code>INF</code> equals <code>INF</code> and <code>-INF</code>
            equals <code>-INF</code>. If either or both of <code>$arg1</code> and <code>$arg2</code> is
            the <code>xs:float</code> or <code>xs:double</code> value <code>NaN</code>, 
            the function returns <code>false</code>. For other values,
            the effect is the same as converting both operands to unlimited-precision
         decimal values, and comparing the resulting decimals for mathematical equality.</p>
      </fos:notes>
      <fos:changes>
         <fos:change issue="986" PR="2218" date="2025-09-29">
            <p>The rules for numeric comparison of mixed types are changed to be fully transitive.</p>
         </fos:change>
      </fos:changes>
   </fos:function>-->
   <!--<fos:function name="numeric-less-than" prefix="op" diff="chg" at="A">
      <fos:signatures>
         <fos:proto name="numeric-less-than" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:numeric"/>
            <fos:arg name="arg2" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="lt" types="numeric" other-operators="le gt ge"
            >Defines the semantics of the
         <code>lt</code> operator when applied to two numeric values, and is also used in defining the
         semantics of <code>le</code>, <code>gt</code>, and <code>ge</code>.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if and only if <code>$arg1</code> is numerically less than
               <code>$arg2</code>. </p>
      </fos:summary>
      <fos:rules>
         <p>If either operand is the <code>xs:double</code> or <code>xs:float</code> value
         <code>NaN</code>, the result is false.</p>
         <p>In all other cases the result is true if and only if <code>fn:compare($arg1, $arg2)</code>
         returns -1 (minus one).</p>
         <!-\-<p>General rules: see <specref ref="op.numeric"/> and <specref ref="comp.numeric"/>.</p>-\->
      </fos:rules>
      <fos:notes>
         <p>For <code>xs:float</code> and <code>xs:double</code> values, positive zero and negative
            zero compare equal. <code>INF</code> equals <code>INF</code> and <code>-INF</code>
            equals <code>-INF</code>. If either or both of <code>$arg1</code> and <code>$arg2</code> is
            the <code>xs:float</code> or <code>xs:double</code> value <code>NaN</code>, 
            the function returns <code>false</code>. For other values,
            the effect is the same as converting both operands to unlimited-precision
         decimal values, and comparing the mathematical relationship of the resulting decimals.</p>
      </fos:notes>
      <fos:changes>
         <fos:change issue="986" PR="2218" date="2025-09-29">
            <p>The rules for numeric comparison of mixed types are changed to be fully transitive.</p>
         </fos:change>
      </fos:changes>
   </fos:function>-->

   <fos:function name="abs" prefix="fn">
      <fos:signatures>
         <fos:proto name="abs" return-type="xs:numeric?">
            <fos:arg name="value" type="xs:numeric?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the absolute value of <code>$value</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="numeric-value-functions"/>.</p>
         <p>If <code>$value</code> is negative the function returns <code>-$value</code>, otherwise it
            returns <code>$value</code>.</p>
         <p>For the four types <code>xs:float</code>,
               <code>xs:double</code>, <code>xs:decimal</code> and <code>xs:integer</code>, it is
            guaranteed that if the type of <code>$value</code> is an instance of type <var>T</var> then
            the result will also be an instance of <var>T</var>. The result <rfc2119>may</rfc2119>
            also be an instance of a type derived from one of these four by restriction. For example, if
            <code>$value</code> is an instance of <code>xs:positiveInteger</code> then the value of
            <code>$value</code>
            <rfc2119>may</rfc2119> be returned unchanged.</p>
         <p>For <code>xs:float</code> and <code>xs:double</code> arguments, if the argument is
            positive zero or negative zero, then positive zero is returned. If the argument is
            positive or negative infinity, positive infinity is returned.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>abs(10.5)</fos:expression>
               <fos:result>10.5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>abs(-10.5)</fos:expression>
               <fos:result>10.5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>abs(-math:log(0))</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="ceiling" prefix="fn">
      <fos:signatures>
         <fos:proto name="ceiling" return-type="xs:numeric?">
            <fos:arg name="value" type="xs:numeric?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Rounds <code>$value</code> upwards to a whole number.</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="numeric-value-functions"/>.</p>
         <p>The function returns the smallest (closest to negative infinity) number with no
            fractional part that is not less than <code>$value</code>.</p>
         <p>For the four types <code>xs:float</code>,
            <code>xs:double</code>, <code>xs:decimal</code> and <code>xs:integer</code>, it is
            guaranteed that if the type of <code>$value</code> is an instance of type <var>T</var> then
            the result will also be an instance of <var>T</var>. The result <rfc2119>may</rfc2119>
            also be an instance of a type derived from one of these four by restriction. For example, if
         <code>$value</code> is an instance of <code>xs:decimal</code> then the result <rfc2119>may</rfc2119>
         be an instance of <code>xs:integer</code>.</p>
         <p>For <code>xs:float</code> and <code>xs:double</code> arguments, if the argument is
            positive zero, then positive zero is returned. If the argument is negative zero, then
            negative zero is returned. If the argument is less than zero and greater than -1,
            negative zero is returned. If the argument is positive or negative infinity, 
            the value of the argument is returned.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>ceiling(10.5)</fos:expression>
               <fos:result>11</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>ceiling(-10.5)</fos:expression>
               <fos:result>-10</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>ceiling(math:log(0))</fos:expression>
               <fos:result>-xs:double('INF')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="floor" prefix="fn">
      <fos:signatures>
         <fos:proto name="floor" return-type="xs:numeric?">
            <fos:arg name="value" type="xs:numeric?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Rounds <code>$value</code> downwards to a whole number.</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="numeric-value-functions"/>.</p>
         <p>The function returns the largest (closest to positive infinity) number with no
            fractional part that is not greater than <code>$value</code>.</p>
         <p>For the four types <code>xs:float</code>,
         <code>xs:double</code>, <code>xs:decimal</code> and <code>xs:integer</code>, it is
         guaranteed that if the type of <code>$value</code> is an instance of type <var>T</var> then
         the result will also be an instance of <var>T</var>. The result <rfc2119>may</rfc2119>
         also be an instance of a type derived from one of these four by restriction. For example, if
         <code>$value</code> is an instance of <code>xs:decimal</code> then the result <rfc2119>may</rfc2119>
         be an instance of <code>xs:integer</code>.</p>
         <p>For <code>xs:float</code> and <code>xs:double</code> arguments, if the argument is
            positive zero, then positive zero is returned. If the argument is negative zero, then
            negative zero is returned. If the argument is positive or negative infinity, 
            the value of the argument is returned.</p>

      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>floor(10.5)</fos:expression>
               <fos:result>10</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>floor(-10.5)</fos:expression>
               <fos:result>-11</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>math:log(0) => floor()</fos:expression>
               <fos:result>-xs:double('INF')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="round" prefix="fn">
      <fos:signatures>
         <fos:proto name="round" return-type="xs:numeric?">
            <fos:arg name="value" type="xs:numeric?"/>
            <fos:arg name="precision" type="xs:integer?" default="0" note="default-on-empty"/>
            <fos:arg name="mode" type="enum('floor',&#xa; 'ceiling',&#xa; 
               'toward-zero',&#xa; 'away-from-zero',&#xa; 'half-to-floor',&#xa; 
               'half-to-ceiling',&#xa; 'half-toward-zero',&#xa; 'half-away-from-zero',&#xa; 'half-to-even')?" default="'half-to-ceiling'" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Rounds a value to a specified number of decimal places, with control over how the rounding
            takes place.</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="numeric-value-functions"/>.</p>
         <p>The function returns a value that is close to <code>$value</code>
               and that is a multiple of ten to the power of minus
               <code>$precision</code>. The default value of <code>$precision</code>
            is zero, in which case the function returns a whole number (but not necessarily
            an <code>xs:integer</code>).</p>
         
         <p>The detailed way in which rounding is performed depends on the value of
            <code>$mode</code>, as follows. Here <var>L</var>
         means the highest multiple of ten to the power
         of minus <code>$precision</code> that is less than or equal to <code>$value</code>,
         <var>U</var> means the lowest multiple of ten to the power
         of minus <code>$precision</code> that is greater than or equal to <code>$value</code>,
         <var>N</var> means the multiple of ten to the power
         of minus <code>$precision</code> that is numerically closest to <code>$value</code>,
         and <term>midway</term> means that <code>$value</code> is equal to the arithmetic
         mean of <var>L</var> and <var>U</var>.</p>
         
         <table role="no-code-break data">
            <caption>Rounding Modes</caption>
            <thead>
               <tr>
                  <th>Rounding Mode</th>
                  <th>Meaning</th>
               </tr>
            </thead>
            <tbody>
               <tr>
                  <td><p><code>'floor'</code></p></td>
                  <td><p>Returns <var>L</var>.</p></td>
               </tr>
               <tr>
                  <td><p><code>'ceiling'</code></p></td>
                  <td><p>Returns <var>U</var>.</p></td>
               </tr>
               <tr>
                  <td><p><code>'toward-zero'</code></p></td>
                  <td><p>Returns <var>L</var> if <code>$value</code> is positive, otherwise <var>U</var>.</p></td>
               </tr>
               <tr>
                  <td><p><code>'away-from-zero'</code></p></td>
                  <td><p>Returns <var>U</var> if <code>$value</code> is positive, otherwise <var>L</var></p></td>
               </tr>
               <tr>
                  <td><p><code>'half-to-floor'</code></p></td>
                  <td><p>Returns <var>N</var>, unless midway, in which case <var>L</var>.</p></td>
               </tr>
               <tr>
                  <td><p><code>'half-to-ceiling'</code></p></td>
                  <td><p>Returns <var>N</var>, unless midway, in which case <var>U</var>. This is the default.</p></td>
               </tr>
               <tr>
                  <td><p><code>'half-toward-zero'</code></p></td>
                  <td><p>Returns <var>N</var>, unless midway, in which case it
                  returns <var>L</var> if <code>$value</code> is positive, otherwise <var>U</var>.</p></td>
               </tr>
               <tr>
                  <td><p><code>'half-away-from-zero'</code></p></td>
                  <td><p>Returns <var>N</var>, unless midway, in which case it
                  returns <var>U</var> if <code>$value</code> is positive, otherwise <var>L</var>.</p></td>
               </tr>
               <tr>
                  <td><p><code>'half-to-even'</code></p></td>
                  <td><p>Returns <var>N</var>, unless midway, in which case it
                  returns whichever of <var>L</var> and <var>U</var> has a last significant
                  digit that is even.</p></td>
               </tr>
            </tbody>
         </table>
         

         <p>For the four types <code>xs:float</code>,
            <code>xs:double</code>, <code>xs:decimal</code> and <code>xs:integer</code>, it is
            guaranteed that if the type of <code>$value</code> is an instance of type <var>T</var> then
            the result will also be an instance of <var>T</var>. The result <rfc2119>may</rfc2119>
            also be an instance of a type derived from one of these four by restriction. For example, if
            <code>$value</code> is an instance of <code>xs:decimal</code> and <code>$precision</code> is 
            less than one, then the result <rfc2119>may</rfc2119>
            be an instance of <code>xs:integer</code>.</p>
         <p>If the second argument is omitted or is the empty sequence,
            the function produces the same result as when
            <code>$precision = 0</code> (that is, it rounds to a whole number).</p>
         <p>When <code>$value</code> is of type <code>xs:float</code> and <code>xs:double</code>:</p>
         <olist>
            <item>
               <p>If <code>$value</code> is <code>NaN</code>, positive or negative zero, or positive or negative
                  infinity, then the result is the same as the argument.</p>
            </item>
            <item>
               <p>For other values, the argument is cast to <code>xs:decimal</code> using an
                  implementation of <code>xs:decimal</code> that imposes no limits on the number of
                  digits that can be represented. The function is applied to this
                     <code>xs:decimal</code> value, and the resulting <code>xs:decimal</code> is
                  cast back to <code>xs:float</code> or <code>xs:double</code> as appropriate to
                  form the function result. If the resulting <code>xs:decimal</code> value is zero,
                  then positive or negative zero is returned according to the sign of
                     <code>$value</code>.</p>
            </item>
         </olist>
         
         <p>There may be <termref def="implementation-defined"/> limits on the precision
         available. If the requested <code>$precision</code> is outside this range, it should
         be adjusted to the nearest value supported by the implementation.</p>

      </fos:rules>
      <fos:notes>
         <p>This function is typically used with a non-zero <code>$precision</code> in financial
            applications where the argument is of type <code>xs:decimal</code>. For arguments of
            type <code>xs:float</code> and <code>xs:double</code> the results may be
            counter-intuitive. For example, consider <code>round(35.425e0, 2)</code>. The result is
            not <code>35.43</code>, as might be expected, but <code>35.42</code>.
            This is because the <code>xs:double</code> written as <code>35.425e0</code>
            has an exact value equal to <code>35.42499999999...</code>, which is closer to
            <code>35.42</code> than to <code>35.43</code>.</p>
         <p>The call <code>round($v, 0, "floor")</code> is equivalent to <code>floor($v)</code>.</p>
         <p>The call <code>round($v, 0, "ceiling")</code> is equivalent to <code>ceiling($v)</code>.</p>
         <p>The call <code>round($v, $p, "half-to-even")</code> is equivalent to <code>round-half-to-even($v, $p)</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>round(2.5)</fos:expression>
               <fos:result>3.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round(2.4999)</fos:expression>
               <fos:result>2.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round(-2.5)</fos:expression>
               <fos:result>-2.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>round(1.125, 2)</fos:expression>
               <fos:result>1.13</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>round(8452, -2)</fos:expression>
               <fos:result>8500</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>round(3.1415e0, 2)</fos:expression>
               <fos:result>3.14e0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>math:log(0) => round()</fos:expression>
               <fos:result>-xs:double('INF')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round(1.7, 0, "floor")</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.7, 0, "floor")</fos:expression>
               <fos:result>-2</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.7, 0, "ceiling")</fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.7, 0, "ceiling")</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.7, 0, "toward-zero")</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.7, 0, "toward-zero")</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.7, 0, "away-from-zero")</fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.7, 0, "away-from-zero")</fos:expression>
               <fos:result>-2</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.125, 2, "half-to-floor")</fos:expression>
               <fos:result>1.12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.125, 2, "half-to-floor")</fos:expression>
               <fos:result>-1.13</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.125, 2, "half-to-ceiling")</fos:expression>
               <fos:result>1.13</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.125, 2, "half-to-ceiling")</fos:expression>
               <fos:result>-1.12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.125, 2, "half-toward-zero")</fos:expression>
               <fos:result>1.12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.125, 2, "half-toward-zero")</fos:expression>
               <fos:result>-1.12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.125, 2, "half-away-from-zero")</fos:expression>
               <fos:result>1.13</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.125, 2, "half-away-from-zero")</fos:expression>
               <fos:result>-1.13</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(1.125, 2, "half-to-even")</fos:expression>
               <fos:result>1.12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>round(-1.125, 2, "half-to-even")</fos:expression>
               <fos:result>-1.12</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1187 1274" PR="1260 1275" date="2024-06-11">
            <p>A third argument has been added, providing control over the rounding mode.</p>
         </fos:change>
         <fos:change issue="1705" PR="1711" date="2025-01-01">
            <p>It is explicitly stated that the limits for <code>$precision</code>
            are implementation-defined.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="round-half-to-even" prefix="fn">
      <fos:signatures>
         <fos:proto name="round-half-to-even" return-type="xs:numeric?">
            <fos:arg name="value" type="xs:numeric?"/>
            <fos:arg name="precision" type="xs:integer?" default="0" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Rounds a value to a specified number of decimal places, rounding to make the last digit
            even if two such values are equally near.</p>
      </fos:summary>
      <fos:rules>
         <p>General rules: see <specref ref="numeric-value-functions"/>.</p>
         <p>The function returns the nearest (that is, numerically closest) value to
               <code>$value</code> that is a multiple of ten to the power of minus
               <code>$precision</code>. If two such values are equally near (e.g. if the fractional
            part in <code>$value</code> is exactly .500...), the function returns the one whose least
            significant digit is even.</p>
         <p>For the four types <code>xs:float</code>,
            <code>xs:double</code>, <code>xs:decimal</code> and <code>xs:integer</code>, it is
            guaranteed that if the type of <code>$value</code> is an instance of type <var>T</var> then
            the result will also be an instance of <var>T</var>. The result <rfc2119>may</rfc2119>
            also be an instance of a type derived from one of these four by restriction. For example, if
            <code>$value</code> is an instance of <code>xs:decimal</code> and <code>$precision</code>
            is less than one, then the result <rfc2119>may</rfc2119>
            be an instance of <code>xs:integer</code>.</p>
         <p>For arguments of type <code>xs:float</code> and <code>xs:double</code>:</p>
         <olist>
            <item>
               <p>If the argument is <code>NaN</code>, positive or negative zero, or positive or
                  negative infinity, then the result is the same as the argument.</p>
            </item>
            <item>
               <p>In all other cases, the argument is cast to <code>xs:decimal</code> using an
                  implementation of <code>xs:decimal</code> that imposes no limits on the number of digits that
                  can be represented. The function is applied to this <code>xs:decimal</code> value,
                  and the resulting <code>xs:decimal</code> is cast back to <code>xs:float</code> or
                     <code>xs:double</code> as appropriate to form the function result. If the
                  resulting <code>xs:decimal</code> value is zero, then positive or negative zero is
                  returned according to the sign of the original argument.</p>
            </item>
         </olist>
         
         <p>There may be <termref def="implementation-defined"/> limits on the precision
         available. If the requested <code>$precision</code> is outside this range, it should
         be adjusted to the nearest value supported by the implementation.</p>

      </fos:rules>
      <fos:notes>
         <p>This function is typically used in financial applications where the argument is of type
               <code>xs:decimal</code>. For arguments of type <code>xs:float</code> and
               <code>xs:double</code> the results may be counter-intuitive. For example, consider
               <code>round-half-to-even(xs:float(150.015), 2)</code>.
               The result is not <code>150.02</code> as might be expected, but <code>150.01</code>.
               This is because the conversion of the
               <code>xs:float</code> value represented by the literal <code>150.015</code> to an
               <code>xs:decimal</code> produces the <code>xs:decimal</code>
               value <code>150.014999389...</code>, which is closer to
               <code>150.01</code> than to <code>150.02</code>.</p>
         <p>From 4.0, the effect of this function can also be achieved by
         calling <function>fn:round</function> with the third argument set to <code>"half-to-even"</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>round-half-to-even(0.5)</fos:expression>
               <fos:result>0.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round-half-to-even(1.5)</fos:expression>
               <fos:result>2.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round-half-to-even(2.5)</fos:expression>
               <fos:result>2.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round-half-to-even(3.567812e+3, 2)</fos:expression>
               <fos:result>3567.81e0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round-half-to-even(4.7564e-3, 2)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>round-half-to-even(35612.25, -2)</fos:expression>
               <fos:result>35600</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>math:log(0) => round-half-to-even()</fos:expression>
               <fos:result>-xs:double('INF')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1705"  PR="1711" date="2025-01-01">
            <p>It is explicitly stated that the limits for <code>$precision</code>
            are implementation-defined.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   
   <fos:function name="divide-decimals" prefix="fn">
      <fos:signatures>
         <fos:proto name="divide-decimals" return-type="record(quotient as xs:decimal, remainder as xs:decimal)">
            <fos:arg name="value" type="xs:decimal"/>
            <fos:arg name="divisor" type="xs:decimal"/>
            <fos:arg name="precision" type="xs:integer?" default="0" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Divides one <code>xs:decimal</code> by another to a defined precision, returning
            both the quotient and the remainder.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a record with two fields:</p>
         <olist>
            <item>
               <p><code>quotient</code> is the <code>xs:decimal</code> value 
                  furthest from zero such that:</p>
               <olist>
                  <item><p><code>quotient</code> is an exact multiple of ten to the power
                  of minus <code>$precision</code>;</p></item>
                  <item><p>the absolute value of <code>quotient</code> 
                     multipled by <code>$divisor</code> is less than or equal to the absolute
                  value of <code>$value</code>;</p></item>
                  <item><p>the sign of <code>quotient</code> is the same as the sign
                     of <code>op:numeric-divide($value, $divisor)</code>.</p></item>
               </olist>
            </item>
            <item>
               <p><code>remainder</code> is the exact result of subtracting <code>quotient</code>
               multiplied by <code>$divisor</code> from <code>$value</code>.</p>
            </item>
         </olist>
         
         <p>There may be <termref def="implementation-defined"/> limits on the precision
         available. If the requested <code>$precision</code> is outside this range, it should
         be adjusted to the nearest value supported by the implementation.</p>
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="AR" code="0001"/> 
            if <code>$divisor</code> is zero.</p>
      </fos:errors>
      
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>divide-decimals(120.6, 60.3, 4)</fos:expression>
               <fos:result>{ "quotient": 2, "remainder": 0 }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>divide-decimals(10, 3)</fos:expression>
               <fos:result>{ "quotient": 3, "remainder": 1 }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>divide-decimals(10, -3)</fos:expression>
               <fos:result>{ "quotient": -3, "remainder": 1 }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>divide-decimals(-10, 3)</fos:expression>
               <fos:result>{ "quotient": -3, "remainder": -1 }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>divide-decimals(-10, -3)</fos:expression>
               <fos:result>{ "quotient": 3, "remainder": -1 }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>divide-decimals(10, 3, 6)</fos:expression>
               <fos:result>{ "quotient": 3.333333, "remainder": 0.000001 }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>divide-decimals(100, 30)</fos:expression>
               <fos:result>{ "quotient": 3, "remainder": 10 }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>divide-decimals(150_862, 7, -3)</fos:expression>
               <fos:result>{ "quotient": 21_000, "remainder": 3_862 }</fos:result>
            </fos:test>           
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1261" PR="1671" date="2025-01-01">
            <p>New in 4.0.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   
   
   <fos:function name="format-integer" prefix="fn">
      <fos:signatures>
         <fos:proto name="format-integer" return-type="xs:string">
            <fos:arg name="value" type="xs:integer?"/>
            <fos:arg name="picture" type="xs:string"/>
            <fos:arg name="language" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="default-language">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Formats an integer according to a given picture string, using the conventions of a given
            natural language if specified.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns a zero-length
            string.</p>
         <p>In all other cases, the <code>$picture</code> argument describes the format in which
               <code>$value</code> is output.</p>
         <p>The rules that follow describe how non-negative numbers are output. If the value of
               <code>$value</code> is negative, the rules below are applied to the absolute value of
               <code>$value</code>, and a minus sign is prepended to the result.</p>

         <p>The value of <code>$picture</code> consists of the following, in order:</p>
         <olist>
            <item><p diff="add" at="2023-04-25">An optional radix, which is an integer in the range 2 to 36, written using ASCII
            digits (<code>0-9</code>) without any leading zero;</p></item>
            <item><p diff="add" at="2023-04-25">A circumflex (<code>^</code>), which is present if the radix is present, and absent otherwise.</p>
               <p diff="add" at="2023-04-25">A circumflex is recognized as marking the presence of a radix only
                  if (a) it is immediately preceded by an integer
                  in the range 2 to 36, and (b) it is
                  followed (somewhere within the primary format token) by an <code>"X"</code>
                  or <code>"x"</code>. In other cases, the circumflex is treated as a grouping separator.
                  For example, the picture <code>9^000</code> outputs the number
                  2345 as <code>"2^345"</code>, whereas <code>9^XXX</code> outputs <code>"3185"</code>.
                  This rule is to ensure backwards compatibility.</p>
            </item>
            <item><p>A primary format token. This is always present and
               <rfc2119>must not</rfc2119> be zero-length.</p></item>
            <item><p>An optional format modifier.</p>
               <p>If the string contains one or more
                  semicolons then the last semicolon is taken as terminating the primary
                  format token, and everything that follows is taken as the format modifier; if the string
                  contains no semicolon then 
                  the format modifier is taken to be absent (which is equivalent to supplying a
                  zero-length string).</p></item>
         </olist>
         

         <p diff="add" at="2023-04-07">If a radix is present, then the primary format token must follow the
            rules for a <var>digit-pattern</var>.</p>
         
         
         <p>The primary format token is classified as one of the following:</p>
         <olist>
            <item>
               <p>A <var>digit-pattern</var> made up of <var>optional-digit-signs</var>,
                     <var>mandatory-digit-signs</var>, and <var>grouping-separator-signs</var>.</p>

               <ulist>
                  <item>
                     <p>The <var>optional-digit-sign</var> is the character <code>#</code>.</p>
                  </item>
                  <item>
                     <p><phrase diff="add" at="2023-04-07">If the radix is absent, then</phrase>
                        a <var>mandatory-digit-sign</var> is a <termref def="character"
                           >character</termref> in Unicode category <var>Nd</var>. All
                           <var>mandatory-digit-signs</var> within the format token
                           <rfc2119>must</rfc2119> be from the same digit family, where a digit
                        family is a sequence of ten consecutive characters in Unicode category <var>Nd</var>,
                        having digit values <code>0</code> through <code>9</code>.
                        Within the format token, these digits are
                        interchangeable: a three-digit number may thus be indicated equivalently by
                        <code>000</code>, <code>001</code>, or <code>999</code>.</p>
                     <p>If the primary format token contains at least one Unicode digit,
                        then the primary format token is taken
                        as a decimal digit pattern, and in this case it <rfc2119>must</rfc2119> match the
                        regular expression <code>^((\p{Nd}|#|[^\p{N}\p{L}])+?)$</code>. If it contains a
                        digit but does not match this pattern, a dynamic error is raised <errorref
                           class="DF" code="1310"/>.</p>
                  </item>
                  <item>
                     <p><phrase diff="add" at="2023-04-07">If the radix (call it <var>R</var>) is 
                        present (including the case where an explicit radix of 10 is used), then</phrase>
                        the character used as the <var>mandatory-digit-sign</var> is either <code>"x"</code>
                        or <code>"X"</code>. If any <var>mandatory-digit-sign</var> is upper-case <code>"X"</code>, then all
                        <var>mandatory-digit-signs</var> must be upper-case <code>"X"</code>. The digit family
                        used in the output comprises the first <var>R</var> characters of the
                        alphabet <code>0123456789abcdefghijklmnopqrstuvwxyz</code>, but using upper-case 
                        letters in place of lower-case if an upper-case <code>"X"</code> is used
                        as the <var>mandatory-digit-sign</var>.</p>
                     <p diff="add" at="2023-04-25">In this case the primary format token <rfc2119>must</rfc2119> match the
                        regular expression <code>^(([Xx#]|[^\p{N}\p{L}])+?)$</code></p>
                  </item>
                  <item>
                     <p>a <var>grouping-separator-sign</var> is a non-alphanumeric character, that
                        is a <termref
                           def="character"
                           >character</termref> whose Unicode category is
                        other than <var>Nd</var>, <var>Nl</var>, <var>No</var>, <var>Lu</var>, <var>Ll</var>, 
                        <var>Lt</var>, <var>Lm</var> or <var>Lo</var>.</p>
                  </item>
               </ulist>

               

               <note>
                  <p>If a semicolon is to be used as a grouping separator, then the primary format
                     token as a whole must be followed by another semicolon, to ensure that the
                     grouping separator is not mistaken as a separator between the primary format
                     token and the format modifier.</p>
               </note>


               <p>There <rfc2119>must</rfc2119> be at least one <var>mandatory-digit-sign</var>.
                  There may be zero or more <var>optional-digit-signs</var>, and (if present) these
                     <rfc2119>must</rfc2119> precede all <var>mandatory-digit-signs</var>. There may
                  be zero or more <var>grouping-separator-signs</var>. A
                     <var>grouping-separator-sign</var>
                  <rfc2119>must not</rfc2119> appear at the start or end of the
                     <var>digit-pattern</var>, nor adjacent to another
                     <var>grouping-separator-sign</var>.</p>

               <p>The corresponding output is a number in the specified radix, using this digit family, with
                  at least as many digits as there are <var>mandatory-digit-signs</var> in the
                  format token. Thus:</p>
                  <ulist>
                     <item><p>A format token <code>1</code> generates the sequence <code>0 1
                        2 ... 10 11 12 ...</code></p></item>
                     <item><p>A format token <code>01</code> (or equivalently,
                        <code>00</code> or <code>99</code>) generates the sequence <code>00 01 02 ...
                           09 10 11 12 ... 99 100 101</code></p></item>
                     <item><p>A format token of <char>U+0661</char>
                        <!--(Arabic-Indic digit one)--> generates the sequence <code>١</code> then <code>٢</code>
                        then <code>٣</code> ...</p></item>
                     <item><p>A format token of <code>16^xx</code> generates the sequence <code>00 01 02 03
                     ... 08 09 0a 0b 0c 0d 0e 0f 10 11 ...</code></p></item>
                     <item><p>A format token of <code>16^X</code> generates the sequence <code>0 1 2 3
                        ... 8 9 A B C D E F 10 11 ...</code></p></item>
                  </ulist>

               <p>The <var>grouping-separator-signs</var> are handled as follows:</p>

               <olist>
                  <item>
                     <p>The position of
                        grouping separators within the format token, counting backwards from the last
                        digit, indicates the position of grouping separators to appear within the
                        formatted number, and the character used as the <var>grouping-separator-sign</var>
                        within the format token indicates the character to be used as the corresponding
                        grouping separator in the formatted number.
                     </p>
                  </item>
                  <item>
                     <p>More specifically, the <term>position</term> of a grouping separator is
                        the number of <var>optional-digit-signs</var> and <var>mandatory-digit-signs</var> appearing
                        between the grouping separator and the right-hand end of the primary format token.</p>
                  </item>
                  <item>
                     <p>Grouping separators are defined to be <term>regular</term> if the following conditions apply:</p>
                     <olist>
                        <item>
                           <p>There is at least one grouping separator.</p>
                        </item>
                        <item>
                           <p>Every grouping separator is the same character (call it <var>C</var>).</p>
                        </item>
                        <item>
                           <p>There is a positive integer <var>G</var> (the grouping size) such that:</p>
                           <olist>
                              <item>
                                 <p>The position of every grouping separator is an integer multiple of <var>G</var>, and</p>
                              </item>
                              <item>
                                 <p>Every positive integer multiple of <var>G</var> that is less than the number of 
                              <var>optional-digit-signs</var> and <var>mandatory-digit-signs</var> in the primary format token
                              is the position of a grouping separator.</p>
                              </item>
                           </olist>
                        </item>
                     </olist>
                  </item>
                  <item>
                     <p>The <term>grouping separator template</term> is a (possibly infinite) set of (position, character) pairs.</p>
                  </item>
                  <item>
                     <p>If grouping separators are regular, then the grouping separator template contains one pair of the form <code>(n×G, C)</code>
                     for every positive integer <var>n</var> where <var>G</var> is the grouping size and <var>C</var> is the grouping character.</p>
                  </item>
                  <item>
                     <p>Otherwise (when grouping separators are not regular), the grouping separator template contains one pair of the form
                     <code>(P, C)</code> for every grouping separator found in the primary formatting token, where <var>C</var> is the grouping
                     separator character and <var>P</var> is its position.</p>
                  </item>
                  <item>
                     <note>
                        <p>If there are no grouping separators, then the grouping separator template is the empty set.</p>
                     </note>
                  </item>
               </olist>


               <p>The number is formatted as follows:</p>

               <olist>
                  <item>
                     <p>Let <var>S/1</var> be the result of formatting the supplied number 
                        <phrase diff="chg" at="2023-04-07">in the appropriate radix:
                        for radix 10 this will be the value obtained</phrase> by casting
                  it to <code>xs:string</code>.</p>
                  </item>
                  <item>
                     <p>Let <var>S/2</var> be the result of padding <var>S/1</var> on the left with as many leading zeroes
                  as are needed to ensure that it contains at least as many digits as the number of <var>mandatory-digit-signs</var>
                  in the primary format token.</p>
                  </item>
                  <item>
                     <p>Let <var>S/3</var> be the result of replacing all decimal digits (0-9) in <var>S/2</var> with the corresponding
                     digits from the selected digit family. <phrase diff="add" at="2023-04-27">(This has no effect when the selected digit family uses ASCII digits (0-9),
                     which will always be the case if a radix is specified.)</phrase></p>
                  </item>
                  <item>
                     <p>Let <var>S/4</var> be the result of inserting grouping separators into <var>S/3</var>: for every (position 
                     <var>P</var>, character <var>C</var>) pair in the grouping separator template where <var>P</var> is less than the number
                  of digits in <var>S/3</var>, insert character <var>C</var> into <var>S/3</var> at position <var>P</var>, counting from 
                  the right-hand end.</p>
                  </item>
                  <item>
                     <p>Let <var>S/5</var> be the result of converting <var>S/4</var> into ordinal form, if an ordinal modifier
                  is present, as described below.</p>
                  </item>
                  <item>
                     <p>The result of the function is then <var>S/5</var>.</p>
                  </item>
               </olist>


            </item>




            <item>
               <p>The format token <code>A</code>, which generates the sequence <code>A B C ... Z AA
                     AB AC...</code>.</p>
            </item>
            <item>
               <p>The format token <code>a</code>, which generates the sequence <code>a b c ... z aa
                     ab ac...</code>.</p>
            </item>
            <item>
               <p>The format token <code>i</code>, which generates the sequence <code>i ii iii iv v
                     vi vii viii ix x ...</code>.</p>
            </item>
            <item>
               <p>The format token <code>I</code>, which generates the sequence <code>I II III IV V
                     VI VII VIII IX X ...</code>.</p>
            </item>
            <item>
               <p>The format token <code>w</code>, which generates numbers written as lower-case
                  words, for example in English, <code>one two three four ...</code>
               </p>
            </item>
            <item>
               <p>The format token <code>W</code>, which generates numbers written as upper-case
                  words, for example in English, <code>ONE TWO THREE FOUR ...</code>
               </p>
            </item>
            <item>
               <p>The format token <code>Ww</code>, which generates numbers written as title-case
                  words, for example in English, <code>One Two Three Four ...</code>
               </p>
            </item>
            <item>
               <p>Any other format token, which indicates a numbering sequence in which that token
                  represents the number 1 (one) (but see the note below).
                  <!-- Where possible (given the constraint that format tokens
						must be alphanumeric, and that they must be distinct) the format token
						used to represent a numbering sequence should be the same as the representation
						of the number 1 (one) in that sequence.-->
                  It is <termref
                     def="implementation-defined"
                     >implementation-defined</termref> which
                  numbering sequences, additional to those listed above, are supported. If an
                  implementation does not support a numbering sequence represented by the given
                  token, it <rfc2119>must</rfc2119> use a format token of <code>1</code>.</p>
               <note>
                  <p>In some traditional numbering sequences additional signs are added to denote
                     that the letters should be interpreted as numbers, for example, in ancient Greek
                      <char>U+0374</char> and sometimes <char>U+0375</char>. These should not be
                     included in the format token.
                  </p>
               </note>
            </item>
         </olist>
         <p>For all format tokens other than a <var>digit-pattern</var>, there 
            <rfc2119>may</rfc2119> be <termref
               def="implementation-defined"
               >implementation-defined</termref> lower and upper bounds on the range of numbers that
            can be formatted using this format token; indeed, for some numbering sequences there may
            be intrinsic limits. For example, the format token <char>U+2460</char> <!--(circled
            digit one, ①)--> has a range imposed by the Unicode character repertoire &#x2014; <phrase>zero to 20</phrase>
            in Unicode versions prior to <phrase>3.2</phrase>, or <phrase>zero to 50</phrase> in subsequent versions. For the numbering
            sequences described above any upper bound imposed by the implementation <rfc2119>must
               not</rfc2119> be less than 1000 (one thousand) and any lower bound must not be
            greater than 1. Numbers that fall outside this range <rfc2119>must</rfc2119> be
            formatted using the format token <code>1</code>.</p>
         <p>The above expansions of numbering sequences for format tokens such as <code>a</code> and
               <code>i</code> are indicative but not prescriptive. There are various conventions in
            use for how alphabetic sequences continue when the alphabet is exhausted, and differing
            conventions for how roman numerals are written (for example, <code>IV</code> versus
               <code>IIII</code> as the representation of the number 4). Sometimes alphabetic
            sequences are used that omit letters such as <code>i</code> and <code>o</code>. This
            specification does not prescribe the detail of any sequence other than those sequences
            consisting entirely of decimal digits.</p>
         <p>Many numbering sequences are language-sensitive. This applies especially to the sequence
            selected by the tokens <code>w</code>, <code>W</code>, and <code>Ww</code>. It also
            applies to other sequences, for example different languages using the Cyrillic alphabet
            use different sequences of characters, each starting with the letter <char>U+0410</char> <!--(Cyrillic
            capital letter A)-->. In such cases, the <code>$language</code> argument specifies which
            language conventions are to be used. If the argument is specified, the value
               <rfc2119>should</rfc2119> be either the empty sequence or a value that would be valid
            for the <code>xml:lang</code> attribute (see <bibref
               ref="xml"
            />). Note that this
            permits the identification of sublanguages based on country codes (from ISO 3166-1) as
            well as identification of dialects and regions within a country.</p>
         <p>The set of languages for which numbering is supported is <termref
               def="implementation-defined"
               >implementation-defined</termref>. If the <code>$language</code> argument is absent, or is
            set to the empty sequence, or is invalid, or is not a language supported by the
            implementation, then the number is formatted using the default language from the dynamic
            context. </p>
         <p>The format modifier <rfc2119>must</rfc2119> be a string that matches the regular
            expression <code>^([co](\(.+\))?)?[at]?$</code>. That is, if it is present it must
            consist of one or more of the following, in order:</p>
         <ulist>
            <item>
               <p>either <code>c</code> or <code>o</code>, optionally followed by a sequence of
                  characters enclosed between parentheses, to indicate cardinal or ordinal numbering
                  respectively, the default being cardinal numbering</p>
            </item>
            <item>
               <p>either <code>a</code> or <code>t</code>, to indicate alphabetic or traditional
                  numbering respectively, the default being <termref
                     def="implementation-defined">implementation-defined</termref>.</p>
            </item>
         </ulist>
         <p>If the <code>o</code> modifier is present, this indicates a request to output ordinal
            numbers rather than cardinal numbers. For example, in English, when used with the format
            token <code>1</code>, this outputs the sequence <code>1st 2nd 3rd 4th ...</code>, and
            when used with the format token <code>w</code> outputs the sequence <code>first second
               third fourth ...</code>.</p>
         <p>The string of characters between the parentheses, if present, is used to select between
            other possible variations of cardinal or ordinal numbering sequences. The interpretation
            of this string is <termref
               def="implementation-defined"
            >implementation-defined</termref>. No error occurs if the implementation does not
            define any interpretation for the defined string.</p>


         <p>It is <termref def="implementation-defined"
            >implementation-defined</termref> what
            combinations of values of the format token, the language, and the cardinal/ordinal
            modifier are supported. If ordinal numbering is not supported for the combination of the
            format token, the language, and the string appearing in parentheses, the request is
            ignored and cardinal numbers are generated instead.</p>

         <p>The use of the <code>a</code> or <code>t</code> modifier disambiguates between numbering
            sequences that use letters. In many languages there are two commonly used numbering
            sequences that use letters. One numbering sequence assigns numeric values to letters in
            alphabetic sequence, and the other assigns numeric values to each letter in some other
            manner traditional in that language. In English, these would correspond to the numbering
            sequences specified by the format tokens <code>a</code> and <code>i</code>. In some
            languages, the first member of each sequence is the same, and so the format token alone
            would be ambiguous. In the absence of the <code>a</code> or <code>t</code> modifier, the
            default is <termref
               def="implementation-defined">implementation-defined</termref>.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DF" code="1310"
               /> if the format token is
            invalid, that is, if it violates any mandatory rules (indicated by an emphasized
               <rfc2119>must</rfc2119> or <rfc2119>required</rfc2119> keyword in the above rules).
            For example, the error is raised if the primary format token contains a digit but does
            not match the required regular expression.</p>
      </fos:errors>
      <fos:notes>
         <olist>
            <item>
               <p>Note the careful distinction between conditions that are errors and conditions where
               fallback occurs. The principle is that an error in the syntax of the format picture will
               be reported by all processors, while a construct that is recognized by some
               implementations but not others will never result in an error, but will instead cause a
               fallback representation of the integer to be used.</p>
            </item>
            <item>
               <p>The following notes apply when a <var>digit-pattern</var> is used:</p>
               <olist>
                  <item>
                     <p>If <var>grouping-separator-signs</var>
                     appear at regular intervals within the format token, then the sequence is extrapolated to
                     the left, so grouping separators will be used in the formatted number at every
                     multiple of <var>N</var>. For example, if the format token is <code>0'000</code>
                     then the number one million will be formatted as <code>1'000'000</code>, while the
                     number fifteen will be formatted as <code>0'015</code>.</p>
                  </item>
                  <item>
                     <p>The only purpose of <var>optional-digit-signs</var> is to mark the position of
                     <var>grouping-separator-signs</var>. For example, if the format token is
                     <code>#'##0</code> then the number one million will be formatted as
                     <code>1'000'000</code>, while the number fifteen will be formatted as
                     <code>15</code>. A grouping separator is included in the formatted number only
                     if there is a digit to its left, which will only be the case if either (a) the
                     number is large enough to require that digit, or (b) the number of
                     <var>mandatory-digit-signs</var> in the format token requires insignificant
                     leading zeros to be present.</p>
                  </item>
                  <item>
                     <p>Grouping separators are <emph>not</emph> designed for effects such as
                     formatting a US telephone number as <code>(365)123-9876</code>. In general they are not 
                     suitable for such purposes because (a) only single characters are allowed, and (b) they
                     cannot appear at the beginning or end of the number.</p>
                  </item>
                  <item>
                     <p>Numbers will never be truncated. Given the <var>digit-pattern</var>
                        <code>01</code>, the number three hundred will be output as <code>300</code>,
                     despite the absence of any <var>optional-digit-sign</var>.</p>
                  </item>

               </olist>
            </item>
            <item>
               <p>The following notes apply when ordinal numbering is selected using the <code>o</code> modifier.</p>
               <p>In some languages, the form of numbers (especially ordinal numbers) varies depending 
                  on the grammatical context: they may have different genders and may decline with the 
                  noun that they qualify. In such cases the string appearing in parentheses after the 
                  letter <code>c</code> or <code>o</code> may be used to indicate the variation of the 
                  cardinal or ordinal number required.</p>

               <p>The way in which the variation is indicated will depend on the conventions of the language.</p>

               <p>For inflected languages that vary the ending of the word, the approach recommended 
                     in the previous version of this specification was to indicate the required ending, 
                     preceded by a hyphen: for example in German, appropriate values might be 
                     <code>o(-e)</code>, <code>o(-er)</code>, <code>o(-es)</code>, <code>o(-en)</code>. 
                  </p>
               <p>Another approach, which might usefully be adopted by an implementation based on the 
                     open-source ICU localization library <bibref
                     ref="ICU"
                     />, or any other library making use of the 
                     Unicode Common Locale Data Repository <bibref
                     ref="CLDR"
                     />, is to allow the value in parentheses 
                     to be the name of a registered numbering rule set for the language in question, 
                     conventionally prefixed with a percent sign: for example, 
                     <code>o(%spellout-ordinal-masculine)</code>, or <code>c(%spellout-cardinal-year)</code>.
                  </p>

            </item>
            <item>
               <p>The following notes apply when the primary format token is neither a <var>digit-pattern</var>
               nor one of the seven other defined format tokens (A, a, i, I, w, W, Ww), but is an arbitrary token
               representing the number 1:</p>
               <p>Unexpected results may occur for traditional numbering. For example, in an
                  implementation that supports traditional numbering system in Greek, the example
                     <code>format-integer(19, "α;t")</code> might return <code>δπιιιι</code> or
                     <code>ιθ</code>, depending upon whether the ancient acrophonic or late antique
                  alphabetic system is supported. </p>
               <p>Unexpected results may also occur for alphabetic numbering. For example, in an
                  implementation that supports alphabetic numbering system in Greek, someone
                  writing <code>format-integer(19, "α;a")</code> might expect the nineteenth Greek
                  letter, <char>U+03C4</char><!-- <code>τ</code>-->, but the implementation might return the eighteenth one, 
                  <char>U+03C3</char><!--#x3C3 <code>σ</code>-->, because the latter is the nineteenth item in the sequence of 
                  lowercase Greek letters in Unicode (the sequence is interrupted because of the final 
                  form of the sigma, <char>U+03C2</char><!--#x3C2 &#x3C2;-->). Because Greek never had a final capital sigma, 
                  Unicode has marked <char>U+03A2</char>, the eighteenth codepoint in the sequence of Greek capital 
                  letters, as reserved, to ensure that every Greek uppercase letter is always 32 codepoints 
                  less than its lowercase counterpart. Therefore, someone writing 
                  <code>format-integer(18, "Α;a")</code> might expect the eighteenth Greek capital letter, 
                  <char>U+03A3</char><!--#x3A3 <code>Σ</code>-->, but an implementation might return <char>U+03A2</char>, 
                  the eighteenth position 
                  in the sequence of Greek capital letters, but unassigned to any character. </p>
            </item>
         </olist>


      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>format-integer(123, '0000')</fos:expression>
               <fos:result>"0123"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>format-integer(123, 'w')</fos:expression>
               <fos:result narrative="true">Depending on the default language, the expression might return
               the string <code>"one hundred and twenty-three"</code></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>format-integer(21, '1;o', 'en')</fos:expression>
               <fos:result>"21st"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>format-integer(14, 'Ww;o(-e)', 'de')</fos:expression>
               <fos:result narrative="true">If supported, might return the string <code>"Vierzehnte"</code>.</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>(1 to 10) ! format-integer(., "1;o(-º)", language:="it")</fos:expression>
               <fos:result narrative="true">This requests ordinal numbering in Italian: if supported, 
                  this should produce the sequence: <code>1º 2º 3º 4º ...</code></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>(1 to 10) ! format-integer(., "Ww;o", language:="it")</fos:expression>
               <fos:result narrative="true">This requests ordinal numbering in Italian, spelled out
                  as words: if supported, 
                  this should produce the sequence: <code>Primo Secondo Terzo Quarto Quinto ...</code></fos:result>
            </fos:test>
         </fos:example>
         
         
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>format-integer(7, 'a')</fos:expression>
               <fos:result>"g"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>format-integer(27, 'a')</fos:expression>
               <fos:result>"aa"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>format-integer(57, 'I')</fos:expression>
               <fos:result>"LVII"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>format-integer(1234, '#;##0;')</fos:expression>
               <fos:result>"1;234"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(1234, '16^xxxx')</fos:expression>
               <fos:result>"04d2"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(1234, '16^X')</fos:expression>
               <fos:result>"4D2"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(12345678, '16^xxxx_xxxx')</fos:expression>
               <fos:result>"00bc_614e"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(12345678, '16^#_xxxx')</fos:expression>
               <fos:result>"bc_614e"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(255, '2^xxxx xxxx')</fos:expression>
               <fos:result>"1111 1111"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(1023, '32^XXXX')</fos:expression>
               <fos:result>"00VV"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(1023, '10^XXXX')</fos:expression>
               <fos:result>"1023"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(1023, '10^00')</fos:expression>
               <fos:result>"10^23"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(-5, '001')</fos:expression>
               <fos:result>"-005"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(-5, 'a')</fos:expression>
               <fos:result>"-e"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="4.0">
               <fos:expression>format-integer(-12, '16^XX')</fos:expression>
               <fos:result>"-0C"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="241" PR="434" date="2023-04-07">
            <p>The function has been extended to allow output in a radix other than 10, for example in hexadecimal.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="format-number" prefix="fn">
      <fos:signatures>
         <fos:proto name="format-number" return-type="xs:string">
            <fos:arg name="value" type="xs:numeric?"/>
            <fos:arg name="picture" type="xs:string"/>
            <fos:arg name="options" type="(xs:string | map(*))?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="decimal-formats namespaces">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string containing a number formatted according to a given picture string
            and decimal format.</p>
      </fos:summary>
      <fos:rules>
         <p>The function formats <code>$value</code> as a string using the <termref
               def="dt-picture-string">picture string</termref> specified by the
               <code>$picture</code> argument and a decimal format.</p>
         <p>The <code>$value</code> argument may be of any numeric data type
            (<code>xs:double</code>, <code>xs:float</code>, <code>xs:decimal</code>, or their
            subtypes including <code>xs:integer</code>). Note that if an <code>xs:decimal</code> is
            supplied, it is not automatically converted to an <code>xs:double</code>, as such
            conversion can involve a loss of precision.</p>
         <p>If the supplied value of the <code>$value</code> argument is the empty sequence, the
            function behaves as if the supplied value were the <code>xs:double</code> value
               <code>NaN</code>.</p>
         <p>If <code>$options</code> is the empty map, then the number is
            formatted using the properties of the unnamed decimal format in the static context.</p>
         <p>For backwards compatibility reasons, the decimal format can be supplied as
         an instance of <code>xs:string</code>. If the value of the <code>$options</code>
         argument is an <code>xs:string</code>, then its value
                  <rfc2119>must</rfc2119> be a string which after removal of leading
                  and trailing whitespace is in the form of an <code>EQName</code>
                  as defined in the XPath 4.0 grammar, that is one of the following:</p>
               <ulist>
                  <item>
                     <p>A lexical QName, which is expanded using the statically known namespaces.
                        The default namespace is not used (no prefix means no namespace).</p>
                  </item>
                  <item>
                     <p>A <code>URIQualifiedName</code> using the syntax <code>Q{uri}local</code>,
                        where the URI can be zero-length to indicate a name in no namespace.</p>
                  </item>
               </ulist>
         <p>The effective value of the <code>$options</code> argument is then the map
         <code>{ 'format-name': $FN }</code> where <code>$FN</code> is the
            <code>xs:QName</code> result of expanding this <code>EQName</code>.</p>
         
         <p>The entries that may appear in the <code>$options</code> map are as follows. 
            The <termref def="option-parameter-conventions"/> apply. The detailed rules
            for the interpretation of each option appear later.</p> 
         <p>In the table, the type <code>xs:string (: matching '.' :)</code>
            represents a single-character string, that is, a restriction of <code>xs:string</code>
            with the facet <code>pattern="."</code>, while the type 
            <code>xs:string (: matching '.|.:.*' :)</code> indicates a string
            that is either a single character, or a single character followed by <char>U+003A</char>
            followed by an arbitrary string. Such a property identifies two values: a single
            character called the <term>marker</term>, which is used to represent the property
            in the picture string; and an arbitrary string called the <term>rendition</term>
            which is used to represent in the property in the result string. In the absence of the colon
            the single character value is used both as the marker and the rendition.</p>
         <p>The default value for absent options (other than
            <code>format-name</code>) is taken from a decimal format in the static context; the default
            values shown in the table are the values used if no specific value is assigned in the
            static context.
         </p>
         
         <fos:options>
            <fos:option key="format-name">
               <fos:meaning>
                  The name of a decimal format in the static context; if absent, the unnamed
                     decimal format in the static context is used. An <code>xs:NCName</code>
                     represents the local part of an <code>xs:QName</code> in no namespace.
               </fos:meaning>
               <fos:type>(xs:NCName | xs:QName)?</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="decimal-separator">
               <fos:meaning>The <term>marker</term> used to represent the decimal point 
                  in the picture string, and the <term>rendition</term> of the decimal point
                  in the formatted number.</fos:meaning>
               <fos:type>xs:string (: matching '.|.:.*' :)</fos:type>
               <fos:default>"."</fos:default>
            </fos:option>
            <fos:option key="grouping-separator">
               <fos:meaning>The <term>marker</term> used to separate groups of digits 
                  in the picture string, and the <term>rendition</term>
                  of the grouping separator in the formatted number.</fos:meaning>
               <fos:type>xs:string (: matching '.|.:.*' :)</fos:type>
               <fos:default>","</fos:default>
            </fos:option>
            <fos:option key="exponent-separator">
               <fos:meaning>The <term>marker</term> used to separate the mantissa from the exponent
                  in scientific notation in the picture 
                  string, and the <term>rendition</term> of the exponent separator
                  in the formatted number.</fos:meaning>
               <fos:type>xs:string (: matching '.|.:.*' :)</fos:type>
               <fos:default>"e"</fos:default>
            </fos:option>
            <fos:option key="infinity">
               <fos:meaning>The string used to represent the value positive or negative infinity 
                  in the formatted number.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"Infinity"</fos:default>
            </fos:option>
            <fos:option key="minus-sign">
               <fos:meaning>The string used as a minus sign in the formatted number if 
                  there is no subpicture for formatting negative numbers.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"-"</fos:default>
            </fos:option>
            <fos:option key="NaN">
               <fos:meaning>The string used to represent the value <code>NaN</code> 
                  in the formatted number.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"NaN"</fos:default>
            </fos:option>
            <fos:option key="percent">
               <fos:meaning>The <term>marker</term> used to indicate the presence of a percent sign 
                  in the picture string, and the <term>rendition</term> of the percent sign 
                  in the formatted number.</fos:meaning>
               <fos:type>xs:string (: matching '.|.:.*' :)</fos:type>
               <fos:default>"%"</fos:default>
            </fos:option>
            <fos:option key="per-mille">
               <fos:meaning><term>marker</term> used to indicate the presence of a per-mille sign 
                  in the picture string, and the <term>rendition</term> of the per-mille sign 
                  in the formatted number.</fos:meaning>
               <fos:type>xs:string (: matching '.|.:.*' :)</fos:type>
               <fos:default>"&#x2030;" (0x2030)</fos:default>
            </fos:option>
            <fos:option key="zero-digit">
               <fos:meaning>Defines the characters used in the picture string to represent a mandatory digit: 
                  for example, if the zero-digit is <code>0</code> then any of the
                  digits <code>0</code> to <code>9</code> may be used (interchangeably) 
                  in the picture string to represent a mandatory digit,
                  and in the formatted number the characters <code>0</code> to <code>9</code> 
                  will be used to represent the digits zero to nine. The value must be
                  a character in Unicode category Nd with decimal digit value 0 (zero).
               </fos:meaning>
               <fos:type>xs:string (: matching '.' :)</fos:type>
               <fos:default>"0"</fos:default>
            </fos:option>
            <fos:option key="digit">
               <fos:meaning>The character used in the picture string to represent 
                  an optional digit.
               </fos:meaning>
               <fos:type>xs:string (: matching '.' :)</fos:type>
               <fos:default>"#"</fos:default>
            </fos:option>
            <fos:option key="pattern-separator">
               <fos:meaning>The character used in the picture string to separate the positive 
                  and negative subpictures.
               </fos:meaning>
               <fos:type>xs:string (: matching '.' :)</fos:type>
               <fos:default>";"</fos:default>
            </fos:option>

         </fos:options>
         
         <p>A base decimal format is established as follows:</p>
         
         <ulist>
            <item><p>If the <code>format-name</code> option is present, then 
               the decimal format in the static context identified by this name.</p></item>
            <item><p>Otherwise, the unnamed decimal format in the static context.</p></item>
         </ulist>
        
         <p>The base decimal format is then modified using the other entries in the
         supplied <code>$options</code> map. <!--The supported
          keys and value types are defined in <specref ref="defining-decimal-format"/>.-->
         </p>


         <p>The evaluation of the <function>fn:format-number</function> function takes place in two
            phases, an analysis phase described in <specref
               ref="analyzing-picture-string"
               /> and a
            formatting phase described in <specref
               ref="formatting-the-number"/>.</p>

         <p>The analysis phase takes as its inputs the <termref def="dt-picture-string"
               >picture
               string</termref> and the variables derived from the relevant decimal format in the
            static context, and produces as its output a number of variables with defined values.
            The formatting phase takes as its inputs the number to be formatted and the variables
            produced by the analysis phase, and produces as its output a string containing a
            formatted representation of the number.</p>

         <p>The result of the function is the formatted string representation of the supplied
            number.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DF" code="1280"/>
            <phrase diff="chg" at="A">if 
            the <code>$options</code> argument is supplied as an <code>xs:string</code>
            that is</phrase> neither a valid lexical QName nor a
            valid <code>URIQualifiedName</code>, or if it uses a prefix that is not found in the
            statically known namespaces; or if the static context does not contain a declaration of
            a decimal format with a matching expanded QName; or if <code>$options?format-name</code>
            is present and the static context does
            not contain a declaration of a decimal format whose name matches <code>$options?format-name</code>.
            If the processor is able to detect the
            error statically (for example, when the argument is supplied as a string literal), then
            the processor <rfc2119>may</rfc2119> optionally signal this as a static error.</p>
         <p>A dynamic error is raised <errorref class="DF" code="1290"/> if a value of
            <code>$format</code> is not valid for the associated property, or if the properties
            of the decimal format resulting from a supplied <code>$options</code>
            map do not have distinct values.</p>
      </fos:errors>
      <fos:notes>
         <p>A string is an ordered sequence of characters, and this specification 
            uses terms such as “left” and “right”, “preceding” and “following” in relation to this ordering, 
            irrespective of the position of the characters when visually rendered on some output medium. 
            Both in the picture string and in the result string, digits with higher significance (that is, 
            representing higher powers of ten) always precede digits with lower significance, even when 
            the rendered text flow is from right to left.</p>
         <p>In previous versions of XSLT and XQuery, decimal formats were typically defined in the
         static context using custom declarations (<code>&lt;xsl:decimal-format></code> in XSLT,
         <code>declare decimal-format</code> in XQuery) and then selected by name in a call on
         <function>fn:format-number</function>. This mechanism remains available, but in 4.0, 
            it may be more convenient to dispense with these
            declarations, and instead to define a decimal format as a map bound to a global
            variable, which can be referenced in the <code>$options</code> argument of the 
            <function>fn:format-number</function> call.</p>
         
         <p>Alternative ways to format an <code>xs:double</code> as a string include:</p>
         <ulist>
            <item><p>Direct casting to string, for example using the constructor function <code>xs:string($number)</code></p></item>
            <item><p>JSON serialization, for example <code>fn:serialize($number, {'method':'json', 'canonical':true()})</code></p></item>
         </ulist>
         <p>In general these will produce different results, for example in the amount of precision that is retained, and
         in the use of exponential (scientific) notation.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>The following examples assume a default decimal format in which the chosen digits are
               the ASCII digits 0-9, the decimal separator is <code>.</code>, the grouping separator is <code>,</code>,
               the minus-sign is <code>-</code>, and the percent-sign is <code>%</code>.</p>
            <fos:test>
               <fos:expression>format-number(12345.6, '#,###.00')</fos:expression>
               <fos:result>"12,345.60"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(12345678.9, '9,999.99')</fos:expression>
               <fos:result>"12,345,678.90"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(123.9, '9999')</fos:expression>
               <fos:result>"0124"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(0.14, '01%')</fos:expression>
               <fos:result>"14%"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(0.14, '01%', { 'percent': '%:pc' })</fos:expression>
               <fos:result>"14pc"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
format-number(12345, '0.0###^0', { 
   'exponent-separator': '^:×10^' 
})</eg></fos:expression>
               <fos:result>"1.2345×10^4"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(-6, '000')</fos:expression>
               <fos:result>"-006"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
format-number(1234567.8, '0.000,0', {
   'grouping-separator': '.',
   'decimal-separator': ','
 })</eg></fos:expression>
               <fos:result>"1.234.567,8"</fos:result>
            </fos:test>
            <p>The following examples assume the existence of a decimal format named
               <code>de</code> in which the grouping separator is <code>.</code> and the
               decimal separator is <code>,</code>:</p>
            <fos:test>
               <fos:expression>format-number(1234.5678, '#.##0,00', { 'format-name': 'de' })</fos:expression>
               <fos:result>"1.234,57"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
format-number(12345, '0,###^0', {
  'format-name': 'de',
  'exponent-separator': '^'
})</eg></fos:expression>
               <fos:result>"1,234^4"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
format-number(12345, '0,###^0', {
  'format-name': 'de',
  'exponent-separator': '^:×10^'
})</eg></fos:expression>
               <fos:result>"1,234×10^4"</fos:result>
            </fos:test>
            <p>The following examples assume that the exponent separator
               in decimal format <code>fortran</code> is <code>E</code>:</p>
            <fos:test>
               <fos:expression>format-number(1234.5678, '00.000E0', 'fortran')</fos:expression>
               <fos:result>"12.346E2"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(0.234, '0.0E0', 'fortran')</fos:expression>
               <fos:result>"2.3E-1"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(0.234, '#.00E0', 'fortran')</fos:expression>
               <fos:result>"0.23E0"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>format-number(0.234, '.00E0', 'fortran')</fos:expression>
               <fos:result>".23E0"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="780" PR="925" date="2024-01-09"><p>The decimal format name can now be supplied 
            as a value of type <code>xs:QName</code>,
            as an alternative to supplying a lexical QName as an instance of <code>xs:string</code>.</p>
         </fos:change>
         <fos:change issue="340 1138" PR="1049 1151" date="2024-03-05"><p>Decimal format parameters 
            can now be supplied directly as a map in the third argument, rather
         than referencing a format defined in the static context.</p></fos:change>
         <fos:change issue="1048" PR="1250" date="2024-06-11">
            <p>For selected properties including <code>percent</code> and <code>exponent-separator</code>,
         it is now possible to specify a single-character marker to be used in the picture string,
         together with a multi-character rendition to be used in the formatted output.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="parse-integer" prefix="fn">
      <fos:signatures>
         <fos:proto name="parse-integer" return-type="xs:integer?">
            <fos:arg name="value" type="xs:string?" example="'12345'"/>
            <fos:arg name="radix" type="xs:integer?" default="10" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Converts a string to an integer, recognizing any radix in the range 2 to 36.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the result is the empty sequence.</p>
         
         <p>The supplied <code>$radix</code> must be in the range 2 to 36 inclusive.</p>
         <p>The string <code>$value</code> is preprocessed by stripping all whitespace characters (including internal whitespace)
         and underscore characters.</p>
         <p>After this process, the supplied value
          must consist of an optional sign (<code>+</code> or <code>-</code>)
         followed by a sequence of one or more generalized digits drawn from the first <code>$radix</code> characters
         in the alphabet <code>0123456789abcdefghijklmnopqrstuvwxyz</code>; upper-case alphabetics
         <code>A-Z</code> may be used in place of their lower-case equivalents.</p>
         <p>The value of a generalized digit corresponds to its position in this alphabet.</p>
         
      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false">
let $alphabet := characters("0123456789abcdefghijklmnopqrstuvwxyz")
let $preprocessed := translate(
  $value, 
  codepoints-to-string((9, 10, 13, 32, 95)), 
  ""
)
let $digits := translate($preprocessed, "+-", "")
let $abs := sum(
  for $char at $p in reverse(characters(lower-case($digits)))
  return (index-of($alphabet, $char) - 1) * xs:integer(math:pow($radix, $p - 1))
)
return if (starts-with($preprocessed, "-")) then -$abs else +$abs                 
      </fos:equivalent>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RG" code="0011"/>
            if <code>$radix</code> is not in the range 2 to 36.</p>
         <p>A dynamic error is raised <errorref class="RG" code="0012"/>
            if, after stripping whitespace and underscores and the optional leading sign, 
            <code>$value</code> is a zero-length string,
            or if it contains a character
         that is not among the first <code>$radix</code> characters in the
            alphabet <code>0123456789abcdefghijklmnopqrstuvwxyz</code>, or the
         upper-case equivalent of such a character.</p>
         <p>A dynamic error is raised <errorref class="CA" code="0003"/>
            if the value of the resulting integer exceeds the implementation-dependent
            limit on the size of an <code>xs:integer</code>.</p>
         
      </fos:errors>
      <fos:notes>
         <p>When <code>$radix</code> takes its default value of <code>10</code>,
            the function delivers the same result as casting <code>$value</code> 
            (after removal of whitespace and underscores) to <code>xs:integer</code>.</p>
         <p>If underscores or whitespace in the input need to be rejected, then
         the string should first be validated, perhaps using <function>fn:matches</function>.</p>
         <p>If other characters may legitimately appear in the input, for example
         a leading <code>0x</code>, then this must first be removed by pre-processing the input.</p>
         <p>If the input uses a different family of digits, then the value should first
         be converted to the required digits using <function>fn:translate</function>.</p>
         <p>A string in the lexical space of <code>xs:hexBinary</code> will always
         be an acceptable input, provided it is not too long. So, for example, the expression
         <code>"1DE=" => xs:base64Binary() => xs:hexBinary() => xs:string() => parse-integer(16)</code>
         can be used to convert the Base 64 value <code>1DE=</code> to the integer 54321, via the 
         hexadecimal string <code>D431</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>parse-integer(" 200 ")</fos:expression>
               <fos:result>200</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer("-20")</fos:expression>
               <fos:result>-20</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer(" +100")</fos:expression>
               <fos:result>100</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer("ff", 16)</fos:expression>
               <fos:result>255</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer("FFFF FFFF", 16)</fos:expression>
               <fos:result>4294967295</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer("-FFFF_FFFF", 16)</fos:expression>
               <fos:result>-4294967295</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer("377", 8)</fos:expression>
               <fos:result>255</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer("101", 2)</fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-integer("vv", 32)</fos:expression>
               <fos:result>1023</fos:result>
            </fos:test>
            <p>Alphabetic base-26 numbering systems (hexavigesimal) can be parsed via translation.
               Note, enumerating systems that do not assign a symbol to zero (e.g., spreadsheet
               columns) must be preprocessed in a different fashion.</p>
            <fos:test>
               <fos:expression><eg>lower-case("AAB")
=> translate("abcdefghijklmnopqrstuvwxyz", "0123456789abcdefghijklmnop")
=> parse-integer(26)</eg></fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
            <p>Digit-based numeration systems comparable to the Arabic numbers 0 through 9 can be
               parsed via translation.</p>
            <fos:test>
               <fos:expression><eg>
translate(value := '٢٠٢٣', replace := '٠١٢٣٤٥٦٧٨٩', with := '0123456789')
=> parse-integer()</eg></fos:expression>
               <fos:result>2023</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="241" PR="434" date="2023-04-25"><p>New in 4.0</p></fos:change>
      </fos:changes>

   </fos:function>
   <fos:function name="pi" prefix="math">
      <fos:signatures>
         <fos:proto name="pi" return-type="xs:double"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an approximation to the mathematical constant <var>π</var>.</p>
      </fos:summary>
      <fos:rules>
         <p>This function returns the <code>xs:double</code> value whose lexical representation is
            3.141592653589793e0</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>2 * math:pi()</fos:expression>
               <fos:result>6.283185307179586e0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>60 * (math:pi() div 180)</fos:expression>
               <fos:result narrative="true">Converts an angle of 60 degrees
               to radians. </fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="e" prefix="math">
      <fos:signatures>
         <fos:proto name="e" return-type="xs:double"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an approximation to the mathematical constant <var>e</var>.</p>
      </fos:summary>
      <fos:rules>
         <p>This function returns the <code>xs:double</code> value whose lexical representation is
            2.718281828459045e0</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test xslt-version="3.0">
               <fos:expression>math:pow(math:e(), 0.05 * 3)</fos:expression>
               <fos:result approx="true">1.161834242728283e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1196 1216" PR="1205 1230" date="2024-05-14"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="exp" prefix="math">
      <fos:signatures>
         <fos:proto name="exp" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value of <var>e</var><sup>x</sup> where <var>x</var> is the argument value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is the mathematical constant <var>e</var> raised to the power of
               <code>$value</code>, as defined in the <bibref
               ref="ieee754-2019"
            /> specification of
            the <code>exp</code> function applied to 64-bit binary floating point values.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of overflow and underflow is defined in <specref ref="op.numeric"/>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:exp(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(1)</fos:expression>
               <fos:result approx="true">2.7182818284590455e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(2)</fos:expression>
               <fos:result>7.38905609893065e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(-1)</fos:expression>
               <fos:result>0.36787944117144233e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(math:pi())</fos:expression>
               <fos:result>23.140692632779267e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp(xs:double('-INF'))</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="exp10" prefix="math">
      <fos:signatures>
         <fos:proto name="exp10" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value of <code>10</code><sup>x</sup>, where <var>x</var> is the supplied argument value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is ten raised to the power of <code>$value</code>, as defined in the
               <bibref
               ref="ieee754-2019"
            /> specification of the <code>exp10</code> function applied
            to 64-bit binary floating point values.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of overflow and underflow is defined in <specref ref="op.numeric"/>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:exp10(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp10(0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp10(1)</fos:expression>
               <fos:result>1.0e1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp10(0.5)</fos:expression>
               <fos:result>3.1622776601683795e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp10(-1)</fos:expression>
               <fos:result>1.0e-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp10(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp10(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:exp10(xs:double('-INF'))</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="log" prefix="math">
      <fos:signatures>
         <fos:proto name="log" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the natural logarithm of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is the natural logarithm of <code>$value</code>, as defined in the
               <bibref
               ref="ieee754-2019"
            /> specification of the <code>log</code> function applied
            to 64-bit binary floating point values.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of <code>divideByZero</code> and <code>invalidOperation</code> exceptions
            is defined in <specref
               ref="op.numeric"
                  />. <phrase>The effect is that if the argument is 
            zero, the result is <code>-INF</code>, and if it is negative, the result is <code>NaN</code></phrase>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:log(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(0)</fos:expression>
               <fos:result>xs:double('-INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(math:exp(1))</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(1.0e-3)</fos:expression>
               <fos:result>-6.907755278982137e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(2)</fos:expression>
               <fos:result>0.6931471805599453e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(-1)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="log10" prefix="math">
      <fos:signatures>
         <fos:proto name="log10" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the base-ten logarithm of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is the base-10 logarithm of <code>$value</code>, as defined in the
               <bibref
               ref="ieee754-2019"
            /> specification of the <code>log10</code> function applied
            to 64-bit binary floating point values.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of <code>divideByZero</code> and <code>invalidOperation</code> exceptions
            is defined in <specref
               ref="op.numeric"
                  />. <phrase>The effect is that if the argument is 
               zero, the result is <code>-INF</code>, and if it is negative, the result is <code>NaN</code></phrase>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:log10(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(0)</fos:expression>
               <fos:result>xs:double('-INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(1.0e3)</fos:expression>
               <fos:result>3.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(1.0e-3)</fos:expression>
               <fos:result>-3.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(2)</fos:expression>
               <fos:result>0.3010299956639812e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(-1)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:log10(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="sqrt" prefix="math">
      <fos:signatures>
         <fos:proto name="sqrt" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the non-negative square root of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is the mathematical non-negative square root of <code>$value</code>
            as defined in the <bibref
               ref="ieee754-2019"
            /> specification of the
               <code>squareRoot</code> function applied to 64-bit binary floating point values.</p>
      </fos:rules>
      <fos:notes>

         <p>The treatment of the <code>invalidOperation</code> exception is defined in <specref
               ref="op.numeric"
               />. The effect is that if the argument is less than zero, the result
            is <code>NaN</code>.</p>

         <p>If <code>$value</code> is positive or negative zero, positive infinity, or
            <code>NaN</code>, then the result is <code>$value</code>. (Negative zero is the only
            case where the result can have negative sign)</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:sqrt(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(0.0e0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(-0.0e0)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(1.0e6)</fos:expression>
               <fos:result>1.0e3</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(2.0e0)</fos:expression>
               <fos:result>1.4142135623730951e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(-2.0e0)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sqrt(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="pow" prefix="math">
      <fos:signatures>
         <fos:proto name="pow" return-type="xs:double?">
            <fos:arg name="x" type="xs:double?"/>
            <fos:arg name="y" type="xs:numeric"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the result of raising the first argument to the power of the second.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$x</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>If <code>$y</code> is an instance of <code>xs:integer</code>, the result is
               <code>$x</code> raised to the power of <code>$y</code> as defined in the <bibref
               ref="ieee754-2019"
            /> specification of the <code>pown</code> function applied to a
            64-bit binary floating point value and an integer.</p>
         <p>Otherwise <code>$y</code> is cast to an <code>xs:double</code>, 
            and the result is <code>$x</code> raised to the power of
               <code>$y</code> as defined in the <bibref
               ref="ieee754-2019"
            /> specification of the
               <code>pow</code> function applied to two 64-bit binary floating point values.</p>
      </fos:rules>
      <fos:notes>

         <p>The treatment of the <code>divideByZero</code> and <code>invalidOperation</code>
            exceptions is defined in <specref
               ref="op.numeric"
            />. Some of the consequences are
            illustrated in the examples below.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:pow((), 93.7)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(2, 3)</fos:expression>
               <fos:result>8.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-2, 3)</fos:expression>
               <fos:result>-8.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(2, -3)</fos:expression>
               <fos:result>0.125e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-2, -3)</fos:expression>
               <fos:result>-0.125e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(2, 0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0, 0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(xs:double('INF'), 0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(xs:double('NaN'), 0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-math:pi(), 0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, 3)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, 4)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-0e0, 3)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0, 4)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, -3)</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, -4)</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-0e0, -3)</fos:expression>
               <fos:result>xs:double('-INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0, -4)</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(16, 0.5e0)</fos:expression>
               <fos:result>4.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(16, 0.25e0)</fos:expression>
               <fos:result>2.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, -3.0e0)</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-0e0, -3.0e0)</fos:expression>
               <fos:result>xs:double('-INF')</fos:result>
               <fos:postamble>Odd-valued whole numbers are treated specially</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, -3.1e0)</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-0e0, -3.1e0)</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, 3.0e0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-0e0, 3.0e0)</fos:expression>
               <fos:result>-0.0e0</fos:result>
               <fos:postamble>Odd-valued whole numbers are treated specially</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(0e0, 3.1e0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-0e0, 3.1e0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-1, xs:double('INF'))</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-1, xs:double('-INF'))</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(1, xs:double('INF'))</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(1, xs:double('-INF'))</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(1, xs:double('NaN'))</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-2.5e0, 2.0e0)</fos:expression>
               <fos:result>6.25e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:pow(-2.5e0, 2.00000001e0)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="sin" prefix="math">
      <fos:signatures>
         <fos:proto name="sin" return-type="xs:double?">
            <fos:arg name="radians" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the sine of the argument. The argument is an angle in radians.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$radians</code> is the empty sequence, the function returns the empty
            sequence.</p>

         <p>Otherwise the result is the sine of <code>$radians</code> (which is treated as an angle in
            radians) as defined in the <bibref
               ref="ieee754-2019"
            /> specification of the
               <code>sin</code> function applied to 64-bit binary floating point values.</p>

      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>invalidOperation</code> and <code>underflow</code> exceptions
            is defined in <specref
               ref="op.numeric"/>. </p>
         <p>If <code>$radians</code> is positive or negative zero, the result is
            <code>$radians</code>.</p>
         <p>If <code>$radians</code> is positive or negative infinity, or <code>NaN</code>,
            then the result is <code>NaN</code>.</p>
         <p>Otherwise the result is always in the range -1.0e0 to +1.0e0</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:sin(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(-0.0e0)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(math:pi() div 2)</fos:expression>
               <fos:result approx="true">1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(-math:pi() div 2)</fos:expression>
               <fos:result approx="true">-1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(math:pi())</fos:expression>
               <fos:result approx="true">0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sin(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="cos" prefix="math">
      <fos:signatures>
         <fos:proto name="cos" return-type="xs:double?">
            <fos:arg name="radians" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the cosine of the argument. The argument is an angle in radians.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$radians</code> is the empty sequence, the function returns the empty
            sequence.</p>
         <p>If <code>$radians</code> is positive or negative infinity, or <code>NaN</code>,
            then the result is <code>NaN</code>.</p>
         <p>Otherwise the result is the cosine of <code>$radians</code> (which is treated as an angle in
            radians) as defined in the <bibref
               ref="ieee754-2019"
            /> specification of the
               <code>cos</code> function applied to 64-bit binary floating point values.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>invalidOperation</code> exception is defined in <specref
               ref="op.numeric"/>. </p>
         <p>If <code>$radians</code> is positive or negative zero, the result is
            <code>$radians</code>.</p>
         <p>If <code>$radians</code>is positive or negative infinity, or <code>NaN</code>,
            then the result is <code>NaN</code>.</p>
         <p>Otherwise the result is always in the range -1.0e0 to +1.0e0</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:cos(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(-0.0e0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(math:pi() div 2)</fos:expression>
               <fos:result approx="true">0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(-math:pi() div 2)</fos:expression>
               <fos:result approx="true">0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(math:pi())</fos:expression>
               <fos:result approx="true">-1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cos(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="tan" prefix="math">
      <fos:signatures>
         <fos:proto name="tan" return-type="xs:double?">
            <fos:arg name="radians" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the tangent of the argument. The argument is an angle in radians.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$radians</code> is the empty sequence, the function returns the empty
            sequence.</p>
         <p>Otherwise the result is the tangent of <code>$radians</code> (which is treated as an angle
            in radians) as defined in the <bibref
               ref="ieee754-2019"
            /> specification of the
               <code>tan</code> function applied to 64-bit binary floating point values.</p>

      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>invalidOperation</code> and <code>underflow</code> exceptions
            is defined in <specref
               ref="op.numeric"/>. </p>
         <p>If <code>$radians</code> is positive or negative infinity, or <code>NaN</code>,
            then the result is <code>NaN</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:tan(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(-0.0e0)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(math:pi() div 4)</fos:expression>
               <fos:result approx="true">1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(-math:pi() div 4)</fos:expression>
               <fos:result approx="true">-1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>1 div math:tan(math:pi() div 2)</fos:expression>
               <fos:result approx="true">0.0e0</fos:result>
               <fos:postamble>Mathematically, <emph>tan(π/2)</emph> is positive infinity. But because <code>math:pi() div 2</code>
                  returns an approximation, the result of <code>math:tan(math:pi() div 2)</code> will be a large
                  but finite number.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>1 div math:tan(-math:pi() div 2)</fos:expression>
               <fos:result approx="true">-0.0e0</fos:result>
               <fos:postamble>Mathematically, <emph>tan(-π/2)</emph> is negative infinity. But because <code>-math:pi() div 2</code>
                  returns an approximation, the result of <code>math:tan(-math:pi() div 2)</code> will be a large
                  but finite negative number.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(math:pi())</fos:expression>
               <fos:result approx="true">0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tan(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="asin" prefix="math">
      <fos:signatures>
         <fos:proto name="asin" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the arc sine of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is the arc sine of <code>$value</code> as defined in the <bibref
               ref="ieee754-2019"
               /> specification of the
            <code>asin</code> function applied to 64-bit binary floating point values. 
            The result is in the range -<var>π</var>/2 to +<var>π</var>/2 radians. </p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>invalidOperation</code> and <code>underflow</code> exceptions
            is defined in <specref
               ref="op.numeric"/>. </p>
         <p>If <code>$value</code> is positive or negative zero, the result is <code>$value</code>.</p>
         <p>If <code>$value</code> is <code>NaN</code>, or if its absolute value is greater than one,
            then the result is <code>NaN</code>.</p>
         <p>In other cases, the result is an <code>xs:double</code> value representing an angle
               <var>θ</var> in radians in the range <code>-math:pi() div 2</code> &lt;=
               <var>θ</var> &lt;= <code>math:pi() div 2</code>. </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:asin(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(-0.0e0)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(1.0e0)</fos:expression>
               <fos:result approx="true">1.5707963267948966e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(-1.0e0)</fos:expression>
               <fos:result approx="true">-1.5707963267948966e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(2.0e0)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:asin(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="acos" prefix="math">
      <fos:signatures>
         <fos:proto name="acos" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the arc cosine of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is the arc cosine of <code>$value</code>, as defined in the <bibref
               ref="ieee754-2019"
               /> specification of the
               <code>acos</code> function applied to 64-bit binary floating point values.
            The result is in the range zero to +<var>π</var> radians.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>invalidOperation</code> exception is defined in <specref
               ref="op.numeric"/>. </p>
         <p>If <code>$value</code> is <code>NaN</code>, or if its absolute value is greater than one,
            then the result is <code>NaN</code>.</p>
         <p>In other cases, the result is an <code>xs:double</code> value representing an angle
               <var>θ</var> in radians in the range <code>0</code> &lt;= <var>θ</var> &lt;=
               <code>math:pi()</code>. </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:acos(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(0)</fos:expression>
               <fos:result approx="true">1.5707963267948966e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(-0.0e0)</fos:expression>
               <fos:result approx="true">1.5707963267948966e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(1.0e0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(-1.0e0)</fos:expression>
               <fos:result approx="true">3.141592653589793e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(2.0e0)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(xs:double('INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:acos(xs:double('-INF'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="atan" prefix="math">
      <fos:signatures>
         <fos:proto name="atan" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the arc tangent of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise the result is the arc tangent of <code>$value</code>, as defined 
            in the <bibref
               ref="ieee754-2019"
               /> specification of the
               <code>atan</code> function applied to 64-bit binary floating point values.
            The result is in the range -<var>π</var>/2
            to +<var>π</var>/2 radians.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>underflow</code> exception is defined in <specref
               ref="op.numeric"/>. </p>
         <p>If <code>$value</code> is positive or negative zero, the result is <code>$value</code>.</p>
         <p>If <code>$value</code> is <code>NaN</code> then the result is <code>NaN</code>.</p>
         <p>In other cases, the result is an <code>xs:double</code> value representing an angle
               <var>θ</var> in radians in the range <code>-math:pi() div 2</code> &lt;=
               <var>θ</var> &lt;= <code>math:pi() div 2</code>. </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:atan(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan(0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan(-0.0e0)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan(1.0e0)</fos:expression>
               <fos:result approx="true">0.7853981633974483e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan(-1.0e0)</fos:expression>
               <fos:result approx="true">-0.7853981633974483e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan(xs:double('NaN'))</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan(xs:double('INF'))</fos:expression>
               <fos:result approx="true">1.5707963267948966e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan(xs:double('-INF'))</fos:expression>
               <fos:result approx="true">-1.5707963267948966e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="atan2" prefix="math">
      <fos:signatures>
         <fos:proto name="atan2" return-type="xs:double">
            <fos:arg name="y" type="xs:double"/>
            <fos:arg name="x" type="xs:double"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the angle in radians subtended at the origin by the point on a plane with
            coordinates (x, y) and the positive x-axis.</p>
      </fos:summary>
      <fos:rules>
         <p>The result is the value of <code>atan2(y, x)</code> as defined in the <bibref
               ref="ieee754-2019"
               /> specification of the <code>atan2</code> function applied to
            64-bit binary floating point values. The result is in the range -<var>π</var>
            to +<var>π</var> radians.</p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>underflow</code> exception is defined in <specref
               ref="op.numeric"/>. The following rules apply when the values are finite and non-zero, 
            (subject to rules for overflow, underflow, and approximation).</p>
         <p>If either argument is <code>NaN</code> then the result is <code>NaN</code>.</p>
         <p diff="chg" at="B">If <code>$x</code> is positive, then  the value of
            <code>atan2($y, $x)</code> is <code>atan($y div $x)</code>.</p>
         <p diff="chg" at="B">If <code>$x</code> is negative, then:</p>
         <ulist diff="chg" at="B">
            <item><p>If <code>$y</code> is positive, then the value of <code>atan2($y, $x)</code> is 
               <code>atan($y div $x) + <var>π</var></code>.</p></item>
            <item><p>If <code>$y</code> is negative, then the value of <code>atan2($y, $x)</code> is 
               <code>atan($y div $x) - <var>π</var></code>.</p></item>
         </ulist>
         <p>Some results for special values of the arguments are shown in the examples below.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:atan2(+0.0e0, 0.0e0)</fos:expression>
               <fos:result>0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(-0.0e0, 0.0e0)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(+0.0e0, -0.0e0)</fos:expression>
               <fos:result>3.141592653589793e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(-0.0e0, -0.0e0)</fos:expression>
               <fos:result>-3.141592653589793e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(-1, 0.0e0)</fos:expression>
               <fos:result>-1.5707963267948966e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(+1, 0.0e0)</fos:expression>
               <fos:result>1.5707963267948966e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(-0.0e0, -1)</fos:expression>
               <fos:result>-3.141592653589793e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(+0.0e0, -1)</fos:expression>
               <fos:result>3.141592653589793e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(-0.0e0, +1)</fos:expression>
               <fos:result>-0.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:atan2(+0.0e0, +1)</fos:expression>
               <fos:result>+0.0e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="sinh" prefix="math">
      <fos:signatures>
         <fos:proto name="sinh" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the hyperbolic sine of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty
            sequence.</p>
         <p>Otherwise the result is the hyperbolic sine of <code>$value</code> as defined in the
            <bibref ref="ieee754-2019"/> specification of the <code>sinh</code> function applied
            to 64-bit binary floating point values. </p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>overflow</code> and <code>underflow</code> exceptions
            is defined in <specref ref="op.numeric"/>. </p>
         <p>If <code>$value</code> is positive or negative zero, the result is
            <code>$value</code>.</p>
         <p>If <code>$value</code> is positive or negative infinity, or <code>NaN</code>,
            the result is <code>NaN</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:sinh(1)</fos:expression>
               <fos:result approx="true">1.1752011936438014e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:sinh(math:pi())</fos:expression>
               <fos:result approx="true">11.548739357257748e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1196 1216" PR="1205 1230" date="2024-05-14"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="cosh" prefix="math">
      <fos:signatures>
         <fos:proto name="cosh" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the hyperbolic cosine of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty
            sequence.</p>
         <p>Otherwise the result is the hyperbolic cosine of <code>$value</code> as defined in the
            <bibref ref="ieee754-2019"/> specification of the <code>cosh</code> function applied
            to 64-bit binary floating point values. </p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>overflow</code> exception
            is defined in <specref ref="op.numeric"/>. </p>
         <p>If <code>$value</code> is positive or negative zero, the result is
            <code>1</code>.</p>
         <p>If <code>$value</code> is positive or negative infinity,
            the result is <code>INF</code>.</p>
         <p>If <code>$value</code> is <code>NaN</code>,
            the result is <code>NaN</code>.</p>
         <p>In other cases, the result is an <code>xs:double</code> in the range
            <code>+1.0</code> to <code>INF</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:cosh(0)</fos:expression>
               <fos:result>1.0e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:cosh(math:pi())</fos:expression>
               <fos:result approx="true">11.591953275521519e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1196 1216" PR="1205 1230" date="2024-05-14"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="tanh" prefix="math">
      <fos:signatures>
         <fos:proto name="tanh" return-type="xs:double?">
            <fos:arg name="value" type="xs:double?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the hyperbolic tangent of the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty
            sequence.</p>
         <p>Otherwise the result is the hyperbolic tangent of <code>$value</code> as defined in the
            <bibref ref="ieee754-2019"/> specification of the <code>tanh</code> function applied
            to 64-bit binary floating point values. </p>
      </fos:rules>
      <fos:notes>
         <p>The treatment of the <code>underflow</code> exception
            is defined in <specref ref="op.numeric"/>. </p>
         <p>If <code>$value</code> is positive or negative zero, the result is
            <code>$value</code>.</p>
         <p>If <code>$value</code> is positive infinity, the result is <code>+1.0</code>.</p>
         <p>If <code>$value</code> is negative infinity, the result is <code>-1.0</code>.</p>
         <p>In other cases, the result is an <code>xs:double</code> in the range
            <code>-1.0</code> to <code>+1.0</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>math:tanh(1)</fos:expression>
               <fos:result approx="true">0.7615941559557649e0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>math:tanh(math:pi())</fos:expression>
               <fos:result approx="true">0.99627207622075e0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1196 1216" PR="1205 1230" date="2024-05-14"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="codepoints-to-string" prefix="fn">
      <fos:signatures>
         <fos:proto name="codepoints-to-string" return-type="xs:string">
            <fos:arg name="values" type="xs:integer*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an <code>xs:string</code> whose characters have supplied <termref
               def="codepoint">codepoints</termref>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the string made up from the <termref def="character"
               >characters</termref> whose Unicode <termref def="codepoint"
               >codepoints</termref> are
            supplied in <code>$values</code>. This will be the zero-length string if <code>$values</code>
            is the empty sequence. </p>
      </fos:rules>
      <fos:errors>
         <p diff="chg" at="2023-06-12">A dynamic error is raised <errorref class="CH" code="0001"
               /> if any of the codepoints in
               <code>$values</code> is not a
               <termref def="dt-permitted-character">permitted character</termref>.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>codepoints-to-string((66, 65, 67, 72))</fos:expression>
               <fos:result>"BACH"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>codepoints-to-string((2309, 2358, 2378, 2325))</fos:expression>
               <fos:result>"अशॊक"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>codepoints-to-string(())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>codepoints-to-string(0)</fos:expression>
               <fos:error-result error-code="FOCH0001"/>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="414" PR="546" date="2023-07-25">
            <p>It is no longer automatically an error if the input
               contains a codepoint that is not valid in XML. Instead, the codepoint
            must be a <termref def="dt-permitted-character"/>. The set of permitted
            characters is <termref def="implementation-defined"/>, but it is
            <rfc2119>recommended</rfc2119> that all Unicode characters should 
               be accepted.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="string-to-codepoints" prefix="fn">
      <fos:signatures>
         <fos:proto name="string-to-codepoints" return-type="xs:integer*">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the sequence of <termref def="codepoint"
               >codepoints</termref> that constitute an
               <code>xs:string</code> value. </p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence of integers, each integer being the Unicode <termref
               def="codepoint">codepoint</termref> of the corresponding <termref def="character"
                  >character</termref> in <code>$value</code>.</p>
         <p>If <code>$value</code> is a zero-length string or the empty sequence, the function returns
            the empty sequence.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>string-to-codepoints("Thérèse")</fos:expression>
               <fos:result>84, 104, 233, 114, 232, 115, 101</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="compare" prefix="fn">
      <fos:signatures>
         <fos:proto name="compare" return-type="xs:integer?">
            <fos:arg name="value1" type="xs:anyAtomicType?"/>
            <fos:arg name="value2" type="xs:anyAtomicType?"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone static-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>-1</code>, <code>0</code>, or <code>1</code>, depending on whether
            the first value is less than, equal to, or greater than the second value.</p>
      </fos:summary>
      <fos:rules>
         <p>The function compares two atomic items <code>$value1</code> and <code>$value2</code> for order, and
            returns the integer value <code>-1</code>, <code>0</code>, or <code>+1</code>,
            depending on whether <code>$value1</code> is less than, equal to, or greater than
            <code>$value2</code>, respectively.</p>
         <p>This function is transitive and symmetric. For example:</p>
         
         <ulist>
            <item><p>If <code>compare(A, B)</code> returns zero, then <code>compare(B, A)</code>
            returns zero.</p></item>
            <item><p>If <code>compare(A, B)</code> returns -1, then <code>compare(B, A)</code>
            returns +1.</p></item>
            <item><p>If <code>compare(A, B)</code> and <code>compare(B, C)</code> both
            return -1, then <code>compare(A, C)</code> also returns -1.</p></item>
         </ulist>
         <p>If either <code>$value1</code> or <code>$value2</code> is the empty sequence,
            the function returns the empty sequence.</p>
         <p>Otherwise, the result is determined as follows:</p>
         <olist>
            <item>
               <p>If <code>$value1</code> is an instance of <code>xs:string</code>,
                  <code>xs:anyURI</code> or <code>xs:untypedAtomic</code>, and if
                  <code>$value2</code> is an instance of <code>xs:string</code>, <code>xs:anyURI</code>
                  or <code>xs:untypedAtomic</code>, the values are compared as strings, and the
                  result reflects the order according to the rules of the collation that is used.</p>
               <p>The collation is determined according to the rules in
                  <specref ref="choosing-a-collation"/>.</p>
               <note><p>Using the default collation may be inappropriate for some strings,
               for example URIs or manufacturing part numbers. In such cases it is safest
               to supply <code>"http://www.w3.org/2005/xpath-functions/collation/codepoint"</code>
               explicitly as the third argument.</p></note>
               <!--<p><phrase diff="chg" at="2023-01-17">When used with the default collation,</phrase>
                  the function defines the semantics of the <code>eq</code>, <code>ne</code>,
                  <code>gt</code>, <code>lt</code>, <code>le</code> and <code>ge</code>
                  operators on <code>xs:string</code> values.</p>-->
            </item>
            <item>
               <p>If both <code>$value1</code> and <code>$value2</code> are instances of
                  <code>xs:numeric</code>, the function relies on a total order, which is
                  defined as follows:</p>
               <olist>
                  <item><p>A value <code>$f</code> of type <code>xs:float</code> is in all cases equal
                     to the value <code>xs:double($f)</code>. The remaining rules therefore only consider
                     instances of <code>xs:double</code> and <code>xs:decimal</code>.</p></item>
                  <item><p><code>NaN</code> is equal to itself and less than any other value.</p></item>
                  <item><p>Negative infinity is equal to itself and less than any other
                     value except <code>NaN</code>.</p></item>
                  <item><p>Positive infinity is equal to itself and greater than any other
                     value.</p></item>
                  <item><p>Negative zero is equal to positive zero.</p></item>
                  <item><p>Other <code>xs:double</code> and <code>xs:decimal</code> values (that is,
                     values other than the infinities, <code>NaN</code>, and negative zero) are ordered
                     according to their mathematical magnitude, the comparison being done without any
                     rounding or loss of precision. This effect can be achieved by converting
                     <code>xs:double</code> values to <code>xs:decimal</code> using an implementation
                     of <code>xs:decimal</code> that imposes no limits on precision or scale, or an
                     implementation whose limits are such that all <code>xs:double</code> values can
                     be represented precisely.</p></item>
               </olist>
               <note>
                  <p>Every <code>xs:double</code> other than <code>NaN</code> and <code>±INF</code>,
                     has a mathematical value of the form <code>m × 2^e</code>, 
                     where <var>m</var> is an integer whose absolute value is less than 2^53, 
                     and <var>e</var> is an integer between -1075 and 970, inclusive. This is the value
                     that is used in comparisons.</p>
                  <p>Practical difficulties arise because the typical string representations of 
                  an <code>xs:double</code>, such as <code>3.1</code>, cannot be precisely
                  represented by values of the form <code>m × 2^e</code>, but are instead converted
                  to the best available approximation, which will often not be exactly equal
                  to an <code>xs:decimal</code> expressed using the same lexical form.</p>
               </note>
            </item>
            <item>
               <p>If both <code>$value1</code> and <code>$value2</code> are instances of
                  <code>xs:boolean</code>, the result is 
                  <code>fn:compare(xs:integer($value1), xs:integer($value2))</code></p>
               
               <note><p>This means that <code>false</code> is 
                  treated as less than <code>true</code>.</p></note>
   
            </item>
            <item>
               <p>If <code>$value1</code> is an instance of <code>xs:hexBinary</code> or
                  <code>xs:base64Binary</code>, and if <code>$value2</code> is an instance of
                  <code>xs:hexBinary</code> or <code>xs:base64Binary</code>, then:</p>
               <olist>
                  <item><p>Let <code>$A</code> be the sequence of integers, in the range (0 to 255), representing
                     the octets of <code>$value1</code>, in order; and let <code>$B</code> similarly
                     be the sequence of integers representing the octets of <code>$value2</code>.</p>
                  </item>
                  <item><p>If <code>$A</code> is empty and <code>$B</code> is empty return zero.</p></item>
                  <item><p>If <code>$A</code> is empty and <code>$B</code> is not empty return -1.</p></item>
                  <item><p>Let <code>$C</code> be the value of <code>fn:compare(fn:head($A), fn:head($B))</code>.</p></item>
                  <item><p>If <code>$C</code> is non-zero, then return <code>$C</code>.</p></item>
                  <item><p>Otherwise, return the result of applying these rules recursively
                  to <code>fn:tail($A)</code> and <code>fn:tail($B)</code></p></item>
                 
               </olist>
            </item>
            
            <item>
               <p>If both <code>$value1</code> and <code>$value2</code> are instances of
                  the same primitive type <var>T</var>, where <var>T</var> is one of the
                  types <code>xs:dateTime</code>, <code>xs:date</code>, <code>xs:time</code>,
                  <code>xs:gYear</code>, <code>xs:gYearMonth</code>, <code>xs:gMonth</code>,
                  <code>gMonthDay</code>, or <code>gDay</code>, then:</p>
               <olist>
                  <item><p>Each of the values is converted to an <code>xs:dateTime</code>
                     value as follows:</p>
                     <olist>
                        <item><p>The value is considered as a tuple with seven fields
                        (year, month, day, hours, minutes, seconds, timezone) as defined by
                        the functions <function>fn:year-from-dateTime</function>,
                        <function>fn:month-from-dateTime</function>, and so on.</p></item>
                        <item><p>Any absent components, other than the timezone, are substituted 
                           with the corresponding components of the 
                           <code>xs:dateTime</code> value <code>1972-01-01T00:00:00</code>
                        to produce an <code>xs:dateTime</code> value.</p></item>
                        <item><p>If the timezone component is absent, it is substituted
                        with the implicit timezone from the dynamic context.</p>
                        
                        <note><p>The <code>xs:dateTime</code> <code>1972-01-01T00:00:00</code>
                        is arbitrary. The only constraint is that the year must be a leap year
                        (so that the <code>xs:gYearMonth</code> value <code>--02-29</code> expands to a valid date).
                        XSD originally chose this as the being historically the first date on which there was a leap second,
                        but this is irrelevant as leap seconds are not supported in XDM.</p></note>
                        
                        </item>
                        
                     </olist>
                  </item>
                  <item><p>The result of the function is then the result of comparing the
                     <term>starting instants</term> of these two <code>xs:dateTime</code>
                     values according to the algorithm defined in section 3.2.7.4 of <bibref
               ref="xmlschema-2"/> (
            <quote>Order relation on dateTime</quote> for <code>xs:dateTime</code> values with
            timezones).</p>
                  </item>
                  
               </olist>
            </item>
            
            <item>
               <p>If both <code>$value1</code> and <code>$value2</code> are instances of
                  <code>xs:duration</code>, then:</p>
               
                  <olist>
                     <item><p>Let <code>$M1</code> and <code>$M2</code>
                  be the months components of the two durations, and let <code>$S1</code>
                  and <code>$S2</code> be the seconds components of the two durations.</p></item>
                     <item><p>Let <code>$C</code> be <code>fn:compare($M1, $M2)</code>.</p></item>
                     <item><p>If <code>$C</code> is non-zero, return <code>$C</code>.</p></item>
                     <item><p>Otherwise, return <code>fn:compare($S1, $S2)</code>.</p></item>
               
               </olist>
               <note><p>The result matches the real-world semantics of durations in many cases,
               for example:</p>
               
               <ulist>
                  <item><p>When both values are zero-length durations.</p></item>
                  <item><p>When both values are have an equal months component (in particular when
                     both have a zero months component).</p></item>
                  <item><p>When both values are have an equal seconds component (in particular when
                     both have a zero seconds component).</p></item>
                  <item><p>When both values have a seconds component that is less than the number
                  of seconds in the shortest month.</p></item>
               </ulist>
                  
                  <p>In other cases the result is well defined and well behaved (for example it
                  is symmetric and transitive) but may be counter-intuitive. For example,
                  one month (<code>PT1M</code>) is considered greater than one hundred days
                  (<code>PT100D</code>).</p>
                  
                  <p>Previous versions of this specification allowed durations to be compared
                  only if both were instances of <code>xs:dateTimeDuration</code> or
                  <code>xs:yearMonthDuration</code>. This requirement has been relaxed in the
                  interests of allowing all atomic items to be sorted; in some applications the actual sort
                  order matters little, so long as it is consistent.</p>
               </note>
            </item>
            
            <item>
               <p>If both <code>$value1</code> and <code>$value2</code> are instances of
                  <code>xs:QName</code>, then:</p>
               
                  <olist>
                     <item><p>Let <code>$N1</code> and <code>$N2</code>
                  be the result of applying the function <function>fn:namespace-uri-from-QName</function>
                        to the two values, and let <code>$L1</code>
                  and <code>$L2</code> be the result of applying the function
                        <function>local-name-from-QName</function> to the two values.</p></item>
                     <item><p>Let <code>$CPC</code> be <code>"http://www.w3.org/2005/xpath-functions/collation/codepoint"</code>.</p></item>
                     <item><p>Let <code>$C</code> be <code>fn:compare($N1, $N2, $CPC)</code>.</p></item>
                     <item><p>If <code>$C</code> is non-zero, return <code>$C</code>.</p></item>
                     <item><p>Otherwise, return <code>fn:compare($L1, $L2, $CPC)</code>.</p></item>
               
                  </olist>
            </item>
            <item>
               <p>If both <code>$value1</code> and <code>$value2</code> are instances of 
                  <code>xs:NOTATION</code>, return <code>fn:compare(xs:QName($value1), xs:QName($value2))</code>.</p>
            </item>
            <item>
               <p>For any other combination of types, a type error
                  <xerrorref spec="XP" class="TY" code="0004"/> is raised. In particular, this means that
               an error is raised when comparing two atomic items that belong to different
               <xspecref spec="DM40" ref="dt-type-family">type families</xspecref>.</p>
            </item>
         </olist>
      </fos:rules>
      <fos:notes>
         <p>For numeric values, consider the <code>xs:double</code> value written as
            <code>0.1e0</code> and the <code>xs:decimal</code> value written as <code>0.1</code>:
            The mathematical magnitude of this <code>xs:double</code> value is 
            <code>0.1000000000000000055511151231257827021181583404541015625</code>.
            Therefore, <code>compare(0.1e0, 0.1)</code> returns <code>+1</code>. By contrast,
            <code>0.1e0 lt 0.1</code> is <code>false</code> and <code>0.1e0 eq 0.1</code>
            is <code>true</code>, because those expressions convert the <code>xs:decimal</code> value
            <code>0.1</code> to the <code>xs:double</code> value <code>0.1e0</code>
            before the comparison.</p>
         <p>Although operations such as sorting and the <function>fn:min</function> and <function>fn:max</function>
            functions invoke <function>fn:compare</function> to perform numeric comparison, these functions
            in some cases treat <code>NaN</code> differently.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>compare('abc', 'abc')</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>compare('Strasse', 'Straße')</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test
               default-collation="http://www.w3.org/2013/collation/UCA?lang=de;strength=primary">
               <fos:expression>compare('Strasse', 'Straße')</fos:expression>
               <fos:result>0</fos:result>
               <fos:postamble>Assuming the default collation equates <quote>ss</quote> and
                  the German letter <quote>ß</quote>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>compare(
  'Strasse',
  'Straße',
  collation({ 'lang': 'de', 'strength': 'primary' })
)</eg></fos:expression>
               <fos:result>0</fos:result>
               <fos:postamble>The specified collation equates <quote>ss</quote> and the German
                  letter <quote>ß</quote>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><![CDATA[compare('text', parse-xml('<xml>text</xml>'))]]></fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(9, 10)</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(123, 123.0)</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:double('NaN'), xs:float('NaN'))</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:double('NaN'), xs:double('-INF'))</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>            
            <fos:test>
               <fos:expression>compare(xs:double('-INF'), -23)</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(1, 1e0)</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(1.1, 1.1e0)</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(1.2, 1.2e0)</fos:expression>
               <fos:result>+1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(9999, xs:double('INF'))</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(false(), true())</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:hexBinary(''), xs:base64Binary(''))</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:hexBinary('0001'), xs:hexBinary('0002'))</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:hexBinary('00FF'), xs:hexBinary('FF'))</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:time('23:59:59'), xs:time('00:00:00'))</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:time('12:00:00Z'), xs:time('13:00:00+01:00'))</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:date('2001-01-01+01:00'), xs:date('2001-01-01+00:00'))</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:duration('P1Y'), xs:duration('P13M'))</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:duration('P1Y'), xs:duration('P1Y3M4D'))</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(xs:duration('P1Y'), xs:duration('P1000D'))</fos:expression>
               <fos:result>+1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(#space, #xml:space)</fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>compare(#Q{http://example.com/ns}index, #Q{http://example.com/ns}xmp:index)</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="893" PR="909" date="2024-01-10">
            <p>The function has been expanded in scope to handle comparison of values other than strings.</p>
         </fos:change>
         <fos:change issue="1608" PR="1611" date="2024-11-26">
            <p>The spec has been corrected to note that the function depends on the implicit timezone.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="codepoint-equal" prefix="fn">
      <fos:signatures>
         <fos:proto name="codepoint-equal" return-type="xs:boolean?">
            <fos:arg name="value1" type="xs:string?"/>
            <fos:arg name="value2" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if two strings are equal, considered codepoint-by-codepoint.</p>
      </fos:summary>
      <fos:rules>
         <p>If either argument is the empty sequence, the function returns the empty sequence. </p>
         <p>Otherwise, the function returns <code>true</code> or <code>false</code> depending on
            whether <code>$value1</code> is equal to 
            <code>$value2</code>, according to the Unicode codepoint collation
               (<code>http://www.w3.org/2005/xpath-functions/collation/codepoint</code>).</p>

      </fos:rules>
      <fos:notes>
         <p>This function allows <code>xs:anyURI</code> values to be compared without having to
            specify the Unicode codepoint collation.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>codepoint-equal("abcd", "abcd")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>codepoint-equal("abcd", "abcd ")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>codepoint-equal("", "")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>codepoint-equal("", ())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>codepoint-equal((), ())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="concat" prefix="fn">
      <fos:signatures>
         <fos:proto name="concat" return-type="xs:string">
            <fos:arg name="values" type="xs:anyAtomicType*" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="||" types="xs:anyAtomicType xs:anyAtomicType"
         > The two-argument form of
         this function defines the semantics of the <code>||</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>variadic</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the concatenation of the arguments, treated as sequences of strings.</p>
      </fos:summary>
      <fos:rules>
         <p>Unlike all other functions, this function is defined to be variadic, as indicated by the
            ellipsis in the function signature.
            Conceptually, there is an infinite set of functions with different numbers of arguments (minimum arity zero,
            maximum arity unbounded):</p>
            
            <ulist>
               <item><p><code>concat()</code> returns a zero-length string, <code>""</code>.</p></item>
               <item><p><code>concat("a")</code> returns <code>"a"</code>.</p></item>
               <item><p><code>concat("a", "b")</code> returns <code>"ab"</code>.</p></item>
               <item><p><code>concat("a", "b", "c")</code> returns <code>"abc"</code>.</p></item>
               <item><p><code>concat("a", "b", "c", "d")</code> returns <code>"abcd"</code>.</p></item>
               <item><p>and so on.</p></item>
            </ulist>
            
            <p>It is equally possible to supply a single argument containing a sequence of strings:</p>
            
            <ulist>
               <item><p><code>concat(())</code> returns a zero-length string, <code>""</code>.</p></item>
               <item><p><code>concat(("a"))</code> returns <code>"a"</code>.</p></item>
               <item><p><code>concat(("a", "b"))</code> returns <code>"ab"</code>.</p></item>
               <item><p><code>concat(("a", "b", "c"))</code> returns <code>"abc"</code>.</p></item>
               <item><p><code>concat(("a", "b", "c", "d"))</code> returns <code>"abcd"</code>.</p></item>
               <item><p>and so on.</p></item>
            </ulist>
            
            <p>More generally, any argument can be a sequence of strings:</p>
            
            <ulist>
               <item><p><code>concat(("a", "b"), "c")</code> returns <code>"abc"</code>.</p></item>
               <item><p><code>concat(("a", "b"), (), ("c", "d"))</code> returns <code>"abcd"</code>.</p></item>
            </ulist>
            
            <p>A static call on the <function>fn:concat</function> function must use positional arguments,
               it cannot use keywords.</p>
            
            <p>Each of the parameters has the required type
            <code>xs:anyAtomicType*</code>. The coercion rules ensure that each supplied argument is first converted to
            a sequence of atomic items by applying atomization. These sequences are then combined (by 
            <xtermref spec="XP40" ref="dt-sequence-concatenation">sequence concatenation</xtermref>) 
               into a single sequence, and each item in the combined sequence
            is converted to a string using the <function>fn:string</function> function. The strings are then concatenated
            with no separator.</p>
         
         
         
         <p>If XPath 1.0 compatibility mode is set to true in the static context of a
            static function call to <function>fn:concat</function>, then each supplied argument 
            <code>$v</code> is first reduced to a single
            string, the result of the expression <code>xs:string($v[1])</code>. This rule applies only to
            static function calls.</p>
         
         <p>A named function reference can be used to create a function item with any arity: for example
         <code>concat#3</code> returns a function item that takes three arguments, which it concatenates.
         Similarly partial function application can be used to construct a function that concatenates fixed and
         variable values: for example <code>concat('[', ?, ']')</code> returns a function item that takes a single
         argument and wraps the string value of this argument in square brackets. Similarly, 
            <code>concat(?, '-', ?)</code> returns a function item of arity two; it returns the string values of
         the two arguments separated by a hyphen.</p>
 
      </fos:rules>
      <fos:notes>
         <p>As mentioned in <specref ref="string-types"
               /> Unicode normalization is not automatically
            applied to the result of <function>fn:concat</function>. If a normalized result is required,
               <function>fn:normalize-unicode</function> can be applied to the <code>xs:string</code>
            returned by <function>fn:concat</function>. The following XQuery:</p>
         <eg xml:space="preserve">
let $v1 := "I plan to go to Mu"
let $v2 := "?nchen in September"
return concat($v1, $v2)</eg>
         <p>where the <code>?</code> represents either the actual Unicode character <char>U+0308</char>
            or the numeric character reference <code>&amp;#x0308;</code>, will return:</p>
         <p>"I plan to go to Mu?nchen in September"</p>
         <p>where the <code>?</code> again represents either the actual Unicode character <char>U+0308</char>
            or the numeric character reference <code>&amp;#x0308;</code>.
            It is worth noting that the returned value is not normalized in NFC; however, it is normalized in NFD.</p>
         <p> However, the following XQuery:</p>
         <eg xml:space="preserve">
let $v1 := "I plan to go to Mu"
let $v2 := "?nchen in September"
return normalize-unicode(concat($v1, $v2))</eg>
         <p>where <code>?</code> represents either the actual Unicode character <char>U+0308</char>
            or the numeric character reference <code>&amp;#x0308;</code>, will return:</p>
         <p><code>"I plan to go to München in September"</code></p>
         <p>This returned result is normalized in NFC.</p>
         <p>Alternatives to the <function>fn:concat</function> function include the concatenation operator
         <code>||</code> (for example <code>$x || '-' || $y</code>), the use of string templates 
         (for example <code>`{ $x }-{ $y }`)</code>, and the <function>fn:string-join</function> function.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>concat('un', 'grateful')</fos:expression>
               <fos:result>"ungrateful"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>concat(('un', 'grateful'))</fos:expression>
               <fos:result>"ungrateful"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>concat(
  'Thy ', (), 'old ', "groans", "", ' ring',
  ' yet', ' in', ' my', ' ancient',' ears.'
)</eg></fos:expression>
               <fos:result>"Thy old groans ring yet in my ancient ears."</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>concat('Ciao!', ())</fos:expression>
               <fos:result>"Ciao!"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>concat('Ingratitude, ', 'thou ', ('marble-hearted', ' fiend!'))</fos:expression>
               <fos:result>"Ingratitude, thou marble-hearted fiend!"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>concat(01, 02, 03, 04, true())</fos:expression>
               <fos:result>"1234true"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>concat()</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>10 || '/' || 6</fos:expression>
               <fos:result>"10/6"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="701" PR="702" date="2023-09-19">
            <p>The function can now take any number of arguments (previously it had to be two or more), and
            the arguments can be sequences of strings rather than single strings.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="string-join" prefix="fn">
      <fos:signatures>
         <fos:proto name="string-join" return-type="xs:string">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="separator" type="xs:string?" default='""' note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string created by concatenating the items in a sequence, with a defined
            separator between adjacent items.</p>
      </fos:summary>
      <fos:rules>
         <p>The coercion rules ensure that the supplied <code>$values</code> argument is first converted to
            a sequence of atomic items by applying atomization.</p>
         <p>The function then returns an <code>xs:string</code> created by casting each item 
            in the atomized sequence to an <code>xs:string</code>, 
            and then concatenating the result strings in order, 
            using the value of <code>$separator</code> as a
            separator between adjacent strings. If <code>$separator</code> is the zero-length
            string, then the items in <code>$values</code> are concatenated without a separator.</p>

      </fos:rules>
      <fos:notes>
         <p>If <code>$values</code> is the empty sequence, the function returns the
            zero-length string.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>string-join(1 to 9)</fos:expression>
               <fos:result>"123456789"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>string-join(('Now', 'is', 'the', 'time', '...'), ' ')</fos:expression>
               <fos:result>"Now is the time ..."</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>string-join(
  ('Blow, ', 'blow, ', 'thou ', 'winter ', 'wind!'),
  ''
)</eg></fos:expression>
               <fos:result>"Blow, blow, thou winter wind!"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>string-join((), 'separator')</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>string-join(1 to 5, ', ')</fos:expression>
               <fos:result>"1, 2, 3, 4, 5"</fos:result>
            </fos:test>
         </fos:example>

         <fos:variable name="doc" id="v-string-join-doc"
            >&lt;doc&gt;&lt;chap&gt;&lt;section xml:id="xyz"/&gt;&lt;/chap&gt;&lt;/doc&gt;</fos:variable>
         <fos:example>
            <fos:test use="v-string-join-doc" spec="XQuery">
               <fos:expression><eg>$doc//@xml:id
! string-join((node-name(), '="', ., '"'))</eg></fos:expression>
               <fos:result>'xml:id="xyz"'</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-string-join-doc" spec="XQuery">
               <fos:expression><eg>$doc//section
! string-join(ancestor-or-self::*/name(), '/')</eg></fos:expression>
               <fos:result>"doc/chap/section"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="substring" prefix="fn">
      <fos:signatures>
         <fos:proto name="substring" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="start" type="xs:double"/>
            <fos:arg name="length" type="xs:double?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the part of <code>$value</code> beginning at the position
            indicated by <code>$start</code> and continuing for the number of <termref
               def="character"
               >characters</termref> indicated by <code>$length</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns
            the zero-length string. </p>
         <p>Otherwise, the function returns a string comprising those <termref def="character"
            >characters</termref> of <code>$value</code> whose index position (counting
            from one) is greater than or equal to <code>$start</code> (rounded to an
            integer), and (if <code>$length</code> is non-empty) less than the sum of
               <code>$start</code> and <code>$length</code> (both rounded to integers).</p>
         <p>The characters returned do not extend beyond <code>$value</code>. If
               <code>$start</code> is zero or negative, only those characters in positions greater
            than zero are returned.</p>
         <p>More specifically, the three argument version of the function returns the characters in
            <code>$value</code> whose position <code>$p</code> satisfies:</p>
         <p>
            <code>fn:round($start) &lt;= $p and $p &lt; fn:round($start) + fn:round($length)</code>
         </p>
         <p>The two argument version of the function assumes that <code>$length</code> is infinite
            and thus returns the <termref
               def="character"
               >characters</termref> in
            <code>$value</code> whose position <code>$p</code> satisfies:</p>
         <p>
            <code>fn:round($start) &lt;= $p</code>
         </p>
         <p>In the above computations, the operators such as <code>&lt;=</code> and <code>+</code>
            are evaluated according to the rules of the XPath 4.0 specification.</p>
 
      </fos:rules>
      <fos:notes>
         <p>The first character of a string is located at position 1, not position 0.</p>
         <p>The second and third arguments allow <code>xs:double</code> values (rather than
         requiring <code>xs:integer</code>) in order to achieve compatibility with XPath 1.0.</p>
         <p>A surrogate pair counts as one character, not two.</p>
         <p>The consequences of supplying values such as <code>NaN</code> or positive or negative
         infinity for the <code>$start</code> or <code>$length</code> arguments follow from the
         above rules, and are not always intuitive.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>substring("motor car", 6)</fos:expression>
               <fos:result>" car"</fos:result>
               <fos:postamble>Characters starting at position 6 to the end of
                     <code>$sourceString</code> are selected.</fos:postamble>
            </fos:test>
            <p/>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("metadata", 4, 3)</fos:expression>
               <fos:result>"ada"</fos:result>
               <fos:postamble>Characters at positions greater than or equal to 4 and less than 7 are
                  selected.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", 1.5, 2.6)</fos:expression>
               <fos:result>"234"</fos:result>
               <fos:postamble>Characters at positions greater than or equal to 2 and less than 5 are
                  selected.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", 0, 3)</fos:expression>
               <fos:result>"12"</fos:result>
               <fos:postamble>Characters at positions greater than or equal to 0 and less than 3 are
                  selected. Since the first position is 1, these are the characters at positions 1
                  and 2.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", 5, -3)</fos:expression>
               <fos:result>""</fos:result>
               <fos:postamble>Characters at positions greater than or equal to 5 and less than 2 are
                  selected.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", -3, 5)</fos:expression>
               <fos:result>"1"</fos:result>
               <fos:postamble>Characters at positions greater than or equal to -3 and less than 2
                  are selected. Since the first position is 1, this is the character at position
                  1.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", 0 div 0E0, 3)</fos:expression>
               <fos:result>""</fos:result>
               <fos:postamble>Since <code>0 div 0E0</code> returns <code>NaN</code>, and
                     <code>NaN</code> compared to any other number returns <code>false</code>, no
                  characters are selected.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", 1, 0 div 0E0)</fos:expression>
               <fos:result>""</fos:result>
               <fos:postamble>As above.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring((), 1, 3)</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", -42, 1 div 0E0)</fos:expression>
               <fos:result>"12345"</fos:result>
               <fos:postamble>Characters at positions greater than or equal to -42 and less than
                     <code>INF</code> are selected.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring("12345", -1 div 0E0, 1 div 0E0)</fos:expression>
               <fos:result>""</fos:result>
               <fos:postamble>Since the value of <code>-INF + INF</code> is <code>NaN</code>, no
                  characters are selected.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The third argument can now be supplied as the empty sequence.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="string-length" prefix="fn">
      <fos:signatures>
         <fos:proto name="string-length" return-type="xs:integer">
            <fos:arg name="value" type="xs:anyAtomicType?" default="fn:string(.)"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of <termref def="character">characters</termref> in a string.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the
            <code>xs:integer</code> value <code>0</code>.
            Otherwise, the value is cast to an <code>xs:string</code>, and an <code>xs:integer</code>
            is returned that reflects the number of <termref def="character">characters</termref>
            in the string.</p>
      </fos:rules>
      <fos:errors>
         <p>If <code>$value</code> is not specified and the context value is <xtermref ref="dt-absent"
               spec="DM40">absent</xtermref>, a type error is raised: <xerrorref spec="XP"
               class="DY" code="0002" type="dynamic"/>.</p>
         <p>As a consequence of the rules given above, a type error is raised 
           <xerrorref spec="XP" class="TY" code="0004" type="type"/> if the context value
            cannot be atomized, or if the result of atomizing the context value is a sequence
            containing more than one atomic item.</p>
      </fos:errors>
      <fos:notes>
         <p>Unlike some programming languages, a <termref def="codepoint"
            >codepoint</termref>
            greater than 65535 counts as one character, not two.</p>
         <p>There are situations where <code>fn:string-length()</code> has a different effect
            from <code>fn:string-length(.)</code>. These situations all involve nodes with
            non-trivial type annotations. For example:</p>
         <ulist><item><p>If the context value
         is an attribute node typed as an <code>xs:integer</code> with the string value <code>000001</code>,
         then <code>fn:string-length()</code> returns <code>6</code>
            (the length of the string value of the node), while 
            <code>fn:string-length(.)</code> returns 1 (the length of the string that results from converting
            the typed value (1) to a string). In earlier versions of this specification this call would have
            failed with a type error.</p></item>
            <item><p>If the context value is the element node <code><![CDATA[<e> NN </e>]]></code>, and has the
            type annotation <code>xs:NCName</code>, then <code>fn:string-length()</code> returns
            4 (the length of the string value of the element node), while <code>fn:string-length(.)</code>
            returns 2 (the length of the typed value of the element node).</p></item>
            <item><p>If the context value is the attribute node <code>ref="A B C"</code>, and has the
            type annotation <code>xs:IDREFS</code>, then <code>fn:string-length()</code> returns
            5 (the length of the string value of the attribute node), while <code>fn:string-length(.)</code>
            raises an error, because the atomized value of the attribute is a sequence of strings,
            and calling the <code>fn:string</code> function on a sequence of strings fails.</p></item>
         </ulist>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>string-length(
  "As long as a piece of string"
)</eg></fos:expression>
               <fos:result>28</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>"ᾧ" => string-length()</eg></fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>"ᾧ" => normalize-unicode("NFD") => string-length()</eg></fos:expression>
               <fos:result>4</fos:result>
               <fos:postamble>For strings that consist of a base character with combining characters, each combining character is length 1.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>string-length(())</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2279" PR="2286" date="2025-11-17"><p>The type of <code>$value</code>
            has been generalized to <code>xs:anyAtomicType?</code>.</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="normalize-space" prefix="fn">
      <fos:signatures>
         <fos:proto name="normalize-space" return-type="xs:string">
            <fos:arg name="value" type="xs:anyAtomicType?" default="string(.)"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>$value</code> with leading and trailing whitespace removed, and
            sequences of internal whitespace reduced to a single space character.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns a zero-length string.
            Otherwise, the value is cast to an <code>xs:string</code>, and a new string is
            constructed by stripping leading and trailing whitespace from the string, and by
            replacing sequences of one or more adjacent whitespace characters with a single space,
            <char>U+0020</char>.</p>
         <p>The whitespace characters are defined in the metasymbol S (Production 3) of <bibref
               ref="xml"/>.</p>
      </fos:rules>
      <fos:errors>
         <p>If no argument is supplied and the context value is
            <xtermref ref="dt-absent" spec="DM40">absent</xtermref>, a type error is raised
            <xerrorref spec="XP" class="DY" code="0002" type="type"/>.</p>
         <p>As a consequence of the rules given above, a type error is raised 
           <xerrorref spec="XP" class="TY" code="0004" type="type"/> if the context value
            cannot be atomized, or if the result of atomizing the context value is a sequence
            containing more than one atomic item.</p>
      </fos:errors>
      <fos:notes>
         <p>The definition of whitespace is unchanged in <bibref ref="xml11"
            />. It is repeated here
         for convenience:</p>
         <p>
            <code>S ::= (#x20 | #x9 | #xD | #xA)+</code>
         </p>
         
         
         <p>There are situations where <code>fn:normalize-space()</code> has a different effect
            from <code>fn:normalize-space(.)</code>. These situations all involve nodes with
            non-trivial type annotations. For example:</p>
         <ulist><item><p>If the context value
         is an attribute node typed as an <code>xs:integer</code> with the string value <code>000001</code>,
         then <code>fn:normalize-space()</code> returns <code>"000001"</code>
            (the string value of the node, whitespace-normalized), while 
            <code>fn:normalize-space(.)</code> returns <code>"1"</code> (the typed value of the node,
            converted to a string and then normalized).</p></item>
            <item><p>If the context value is the attribute node <code>ref=" A  B C "</code>, and has the
            type annotation <code>xs:IDREFS</code>, then <code>fn:normalize-space()</code> returns
            <code>"A B C"</code> (the string value of the attribute node, whitespace-normalized), 
               while <code>fn:normalize-space(.)</code>
            raises an error, because the typed value of the attribute is a sequence of strings,
            and calling the <function>fn:string</function> function on a sequence of strings fails.</p></item>
         </ulist>
         
         <p>The effect of <code>fn:normalize-space</code> is exactly the same as the effect of
         the <code>whitespace=collapse</code> facet in XSD. Since this facet is implicit for most
         XSD data types (with the notable exception of <code>xs:string</code> itself), nodes that are
         validated against types other than <code>xs:string</code> will tend to be implicitly
         in the form that <function>normalize-string</function> generates. Confusingly,
         the XSD type <code>xs:normalizedString</code> uses the facet <code>whitespace=replace</code>,
         which does <emph>not</emph> have the same effect as the <function>normalize-space</function>
         function: it replaces all whitespace characters by <char>U+0020</char>, but does not remove
         leading or trailing spaces, nor does it merge adjacent spaces.</p>
         
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>normalize-space(" The    wealthy curled darlings
           of    our    nation. ")</eg></fos:expression>
               <fos:result>"The wealthy curled darlings of our nation."</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>normalize-space(())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2279" PR="2286" date="2025-11-17"><p>The type of <code>$value</code>
            has been generalized to <code>xs:anyAtomicType?</code>.</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="normalize-unicode" prefix="fn">
      <fos:signatures>
         <fos:proto name="normalize-unicode" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="form" type="xs:string?" default='"NFC"' note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>$value</code> after applying Unicode normalization.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the
            zero-length string.</p>
         <p>Otherwise, the function returns <code>$value</code> normalized according to
            the rules of the normalization form identified by the value of
               <code>$form</code>.</p>
         <p>The effective value of <code>$form</code> is the value of the expression
               <code>fn:upper-case(fn:normalize-space($form))</code>.</p>

         <ulist>
            <item>
               <p>If the effective value of <code>$form</code> is <quote>NFC</quote>,
                  then the function returns <code>$value</code> converted to Unicode
                  Normalization Form C (NFC).</p>
            </item>
            <item>
               <p>If the effective value of <code>$form</code> is <quote>NFD</quote>,
                  then the function returns <code>$value</code> converted to Unicode
                  Normalization Form D (NFD).</p>
            </item>
            <item>
               <p>If the effective value of <code>$form</code> is <quote>NFKC</quote>,
                  then the function returns <code>$value</code> in Unicode Normalization
                  Form KC (NFKC).</p>
            </item>
            <item>
               <p>If the effective value of <code>$form</code> is <quote>NFKD</quote>,
                  then the function returns <code>$value</code> converted to Unicode
                  Normalization Form KD (NFKD).</p>
            </item>
            <item>
               <p>If the effective value of <code>$form</code> is
                     <quote>FULLY-NORMALIZED</quote>, then the function returns 
                  <code>$value</code> converted to fully normalized form. </p>
            </item>
            <item>
               <p>If the effective value of <code>$form</code> is the zero-length
                  string, no normalization is performed and <code>$value</code> is returned.</p>
            </item>
         </ulist>
         <p>Normalization forms NFC, NFD, NFKC, and NFKD, and the algorithms to be used for
            converting a string to each of these forms, are defined in <bibref
               ref="UNICODE-TR15"/>.</p>
         <p>The motivation for normalization form FULLY-NORMALIZED is explained in <bibref
               ref="charmod-normalization"
            />. However, as that specification did not progress beyond
            working draft status, the normative specification is as follows:</p>
         <ulist>
            <item>
               <p>A string is <term>fully-normalized</term> if (a) it is in normalization form NFC
                  as defined in <bibref
                     ref="UNICODE-TR15"
                  />, and (b) it does not start
                  with a composing character.</p>
            </item>
            <item>
               <p>A composing character is a character that is one or both of the following:</p>
               <ulist>
                  <item>
                     <p>the second character in the canonical decomposition mapping of some
                        character that is not listed in the Composition Exclusion Table defined in
                        <bibref
                           ref="UNICODE-TR15"/>;</p>
                  </item>
                  <item>
                     <p>of non-zero canonical combining class (as defined in <bibref ref="Unicode"
                        />).</p>
                  </item>

               </ulist>
            </item>
            <item>
               <p>A string is converted to FULLY-NORMALIZED form as follows:</p>
               <ulist>
                  <item>
                     <p>if the first character in the string is a composing character, prepend a
                        single space (x20);</p>
                  </item>
                  <item>
                     <p>convert the resulting string to normalization form NFC.</p>
                  </item>
               </ulist>
            </item>
         </ulist>

         <p>Conforming implementations <rfc2119>must</rfc2119> support normalization form <code>NFC</code> and
               <rfc2119>may</rfc2119> support normalization forms <code>NFD</code>, <code>NFKC</code>, <code>NFKD</code>, and
            <code>FULLY-NORMALIZED</code>. They <rfc2119>may</rfc2119> also support other normalization forms
            with <termref
               def="implementation-defined">implementation-defined</termref> semantics. </p>
         <p>It is <termref def="implementation-defined"
               >implementation-defined</termref> which
            version of Unicode (and therefore, of the normalization algorithms and their underlying
            data) is supported by the implementation. See <bibref
               ref="UNICODE-TR15"
               /> for
            details of the stability policy regarding changes to the normalization rules in future
            versions of Unicode. If the input string contains codepoints that are unassigned in the
            relevant version of Unicode, or for which no normalization rules are defined, the
               <function>fn:normalize-unicode</function> function leaves such codepoints unchanged. If the
            implementation supports the requested normalization form then it <rfc2119>must</rfc2119>
            be able to handle every input string without raising an error.</p>
      </fos:rules>
      <fos:errors>
         <p>A <phrase>dynamic</phrase> error is raised <errorref class="CH" code="0003"
               /> if the
            effective value of the <code>$form</code> argument is not one of the values
            supported by the implementation.</p>
      </fos:errors>
   </fos:function>
   <fos:function name="upper-case" prefix="fn">
      <fos:signatures>
         <fos:proto name="upper-case" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Converts a string to upper case.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the zero-length string is
            returned.</p>
         <p>Otherwise, the function returns <code>$value</code> after translating every
               <termref
               def="character"
               >character</termref> to its upper-case correspondent as
            defined in the appropriate case mappings section in the Unicode standard <bibref
               ref="Unicode"
            />. For versions of Unicode beginning with the 2.1.8 update, only
            locale-insensitive case mappings should be applied. Beginning with version 3.2.0 (and
            likely future versions) of Unicode, precise mappings are described in default case
            operations, which are full case mappings in the absence of tailoring for particular
            languages and environments. Every lower-case character that does not have an upper-case
            correspondent, as well as every upper-case character, is included in the returned value
            in its original form. </p>
      </fos:rules>
      <fos:notes>
         <p>Case mappings may change the length of a string. In general, the
               <function>fn:upper-case</function> and <function>fn:lower-case</function> functions are not inverses
            of each other: <code>fn:lower-case(fn:upper-case($s))</code> is not guaranteed to
            return <code>$s</code>, nor is <code>fn:upper-case(fn:lower-case($s))</code>. The
            character <char>U+0131</char> (used in Turkish) 
            <!--Latin small letter dotless i (ı, U+0131, used in Turkish)--> is perhaps the most prominent
            lower-case letter which will not round-trip. The character <char>U+0130</char>
            <!--Latin capital letter i with dot above (İ, U+0130)-->
            is the most prominent upper-case letter which will not round trip; there are others,
            such as <char>U+1E9E</char><!--Latin capital letter sharp S (ẞ, U+1E9E)-->, which was introduced in Unicode 5.1.</p>
         <p> These functions may not always be linguistically appropriate (e.g. Turkish i without
            dot) or appropriate for the application (e.g. titlecase). In cases such as Turkish, a
            simple translation should be used first.</p>
         <p> Because the function is not sensitive to locale, results will not always match user
            expectations. In Quebec, for example, the standard uppercase equivalent of <code>è</code> is <code>È</code>,
            while in metropolitan France it is more commonly <code>E</code>; only one of these is supported by
            the functions as defined.</p>
         <p> Many characters of class Ll lack uppercase equivalents in the Unicode case mapping
            tables; many characters of class Lu lack lowercase equivalents.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>upper-case("abCd0")</fos:expression>
               <fos:result>"ABCD0"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="lower-case" prefix="fn">
      <fos:signatures>
         <fos:proto name="lower-case" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Converts a string to lower case.</p>
      </fos:summary>
      <fos:rules>
         <p>If t<code>$value</code> is the empty sequence, the zero-length string is
            returned.</p>
         <p>Otherwise, the function returns <code>$value</code> after translating every
               <termref
               def="character"
               >character</termref> to its lower-case correspondent as
            defined in the appropriate case mappings section in the Unicode standard <bibref
               ref="Unicode"
            />. For versions of Unicode beginning with the 2.1.8 update, only
            locale-insensitive case mappings should be applied. Beginning with version 3.2.0 (and
            likely future versions) of Unicode, precise mappings are described in default case
            operations, which are full case mappings in the absence of tailoring for particular
            languages and environments. Every upper-case character that does not have a lower-case
            correspondent, as well as every lower-case character, is included in the returned value
            in its original form. </p>
      </fos:rules>
      <fos:notes>
         <p>Case mappings may change the length of a string. In general, the
               <function>fn:upper-case</function> and <function>fn:lower-case</function> functions are not inverses
            of each other: <code>fn:lower-case(fn:upper-case($s))</code> is not guaranteed to
            return <code>$s</code>, nor is <code>fn:upper-case(fn:lower-case($s))</code>. The
            character <char>U+0131</char> (used in Turkish)<!--Latin small letter dotless i (ı, U+0131, used in Turkish)--> 
            is perhaps the most prominent
            lower-case letter which will not round-trip. The character <char>U+0130</char>
            <!--Latin capital letter i with dot above (İ, U+0130)-->
            is the most prominent upper-case letter which will not round trip; there are others,
            such as <char>U+1E9E</char><!-- Latin capital letter sharp S (ẞ, U+1E9E)-->, which was introduced in Unicode 5.1.</p>
         <p> These functions may not always be linguistically appropriate (e.g. Turkish i without
            dot) or appropriate for the application (e.g. titlecase). In cases such as Turkish, a
            simple translation should be used first.</p>
         <p> Because the function is not sensitive to locale, results will not always match user
            expectations. In Quebec, for example, the standard uppercase equivalent of <code>è</code> is <code>È</code>,
            while in metropolitan France it is more commonly <code>E</code>; only one of these is supported by
            the functions as defined.</p>
         <p> Many characters of class Ll lack uppercase equivalents in the Unicode case mapping
            tables; many characters of class Lu lack lowercase equivalents.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>lower-case("ABc!D")</fos:expression>
               <fos:result>"abc!d"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="translate" prefix="fn">
      <fos:signatures>
         <fos:proto name="translate" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="replace" type="xs:string"/>
            <fos:arg name="with" type="xs:string"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>$value</code> modified by replacing or removing individual
            characters. </p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the
            zero-length string.</p>
         <p>Otherwise, the function returns a result string constructed by processing each <termref
               def="character"
            >character</termref> in <code>$value</code>, in order,
            according to the following rules:</p>
         <olist>
            <item>
               <p>If the character does not appear in <code>$replace</code> then it
                  is added to the result string unchanged.</p>
            </item>
            <item>
               <p>If the character first appears in <code>$replace</code> at some
                  position <emph>M</emph>, where the value of <code>$with</code> is
                     <emph>M</emph> or more characters in length, then the character at position
                     <emph>M</emph> in <code>$with</code> is added to the result string.</p>
            </item>
            <item>
               <p>If the character first appears in <code>$replace</code> at some
                  position <emph>M</emph>, where <code>$with</code> is less than
                     <emph>M</emph> characters in length, then the character is omitted from the
                  result string.</p>
            </item>
         </olist>
      </fos:rules>
      <fos:notes>
         <p>If <code>$replace</code> is the zero-length string then the function returns
               <code>$value</code> unchanged.</p>
         <p>If a character occurs more than once in <code>$replace</code>, then the first
            occurrence determines the action taken.</p>
         <p>If <code>$with</code> is longer than <code>$replace</code>, the excess
            characters are ignored.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>translate("bar", "abc", "ABC")</fos:expression>
               <fos:result>"BAr"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>translate("--aaa--", "abc-", "ABC")</fos:expression>
               <fos:result>"AAA"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>translate("abcdabc", "abc", "AB")</fos:expression>
               <fos:result>"ABdAB"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="hash" prefix="fn" at="2024-01-10" diff="add">
      <fos:signatures>
         <fos:proto name="hash" return-type="xs:hexBinary?">
            <fos:arg name="value" type="(xs:string | xs:hexBinary | xs:base64Binary)?"/>
            <fos:arg name="algorithm" type="xs:string?" default='"MD5"' note="default-on-empty"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the results of a specified hash, checksum, or
            cyclic redundancy check function applied to the input.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>If <code>$value</code> is an instance of <code>xs:string</code>, it is converted to a sequence
            of octets on the basis of UTF-8 encoding. If <code>$value</code> is an instance of
               <code>xs:base64Binary</code> or <code>xs:hexBinary</code>, it is converted to a sequence of
            octets. </p>
         <p>The <code>$algorithm</code> argument determines the algorithm to be used to
            calculate a checksum, hash, or cyclic redundancy check. The effective value of the
            algorithm is determined by passing the value through
            <code>fn:upper-case(fn:normalize-space())</code>. </p>
         <p>Conforming implementations <rfc2119>must</rfc2119> support the following
            options and the functions referred to by them:</p>
         <ulist> 
            <item><p><code>MD5</code>: the MD5 Message-Digest algorithm, defined by <bibref
               ref="rfc6151"/> (update to <bibref ref="rfc1321"/>).</p></item>
            <item><p><code>SHA-1</code>: the SHA-1 algorithm, defined by <bibref
               ref="fips180-4"/>. </p></item>
            <item><p><code>SHA-256</code>: the SHA-256 algorithm, defined by <bibref
               ref="fips180-4"/>. </p></item>
            <item><p><code>BLAKE3</code>: the BLAKE3 algorithm defined by <bibref 
               ref="BLAKE3"/>.</p></item>
            <item><p><code>CRC-32</code>: the CRC-32 algorithm, defined by <bibref
               ref="ieee802-3"/>. It delivers a 32 bit unsigned integer, which this function
               returns as a 4-octet <code>xs:hexBinary</code> value representing this integer in
               big-endian order (that is, most significant byte first).</p>
               <note><p>Some libraries, notably <code>System.IO.Hashing.Crc32</code> in .NET, return
               the result in little-endian order.</p></note></item>
         </ulist>
         <p>Conforming implementations <rfc2119>may</rfc2119> support other checksum and
            hash functions with implementation-defined semantics.
            The <code>$options</code> argument, if present, defines additional parameters
            controlling how the process is conducted.</p>
         <p>The function returns as <code>xs:hexBinary</code> the octets returned by passing
            <code>$value</code> as an octet sequence through the selected algorithm.
            The process is followed even if the input octet sequence is empty.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="HA" code="0001"/> if the effective value of the
            option <code>algorithm</code> is not one of the values supported by the implementation.</p>
      </fos:errors>
      <fos:notes>
         <p>It is common for secure algorithms to be cryptographically broken, as has happened to
            the algorithms <code>MD5</code>, <code>SHA-1</code>, and <code>SHA-256</code>. 
            And the <code>CRC-32</code> algorithm is not intended for cryptographic purposes. 
            Developers are responsible for ensuring that the algorithm chosen meets any expected
            security protocols, if relevant.</p>
         <p>The <code>BLAKE3</code> algorithm is included in the list of hashing algorithms 
            because at the time of writing it appears to be a promising candidate as a secure and
            fast algorithm  that shows signs of gaining widespread support. 
            However, this is a fast moving field and the community group recognizes that this
            decision might eventually not stand the test of time. 
            As the technology evolves in the future, implementations are free to drop support
            for this algorithm and substitute another that appears to better meet requirements.</p>
         <p>Additional security practices, such as salting, may be applied as a preprocessing step,
            or <code>fn:hash()</code> can be incorporated into more complex functions.</p>
         <p>In most cases, the <code>xs:hexBinary</code> output of the function will be sought in
            string form. Because of serialization rules, casting to a string renders the hash in
            uppercase, and rendering in lowercase (as adopted by <bibref ref="rfc1321"/> and 
            <bibref ref="fips180-4"/>) requires further adjustment.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="doc" id="v-hash-doc"><![CDATA[<doc>abc</doc>]]></fos:variable>
         <fos:variable name="salt" id="v-hash-salt" select="&quot;D;%yL9TS:5PalS/d&quot;"/>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hash("abc")</eg></fos:expression>
               <fos:result>xs:hexBinary("900150983CD24FB0D6963F7D28E17F72")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("ABC")</eg></fos:expression>
               <fos:result>xs:hexBinary("902FBDD2B1DF0C4F70B4A5D23525E932")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("")</eg></fos:expression>
               <fos:result>xs:hexBinary("D41D8CD98F00B204E9800998ECF8427E")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("ABC", "SHA-1")</eg></fos:expression>
               <fos:result>xs:hexBinary("3C01BDBB26F358BAB27F267924AA2C9A03FCFDB8")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("ABC", "BLAKE3") 
=> string()
=> lower-case()</eg></fos:expression>
               <fos:result>"d1717274597cf0289694f75d96d444b992a096f1afd8e7bbfa6ebb1d360fedfc"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("ABC", "BLAKE3") 
=> xs:base64Binary()
=> string()</eg></fos:expression>
               <fos:result>"0XFydFl88CiWlPddltREuZKglvGv2Oe7+m67HTYP7fw="</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("ABC", "sha-256")
=> string()</eg></fos:expression>
               <fos:result>"B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("ABC", "sha-256")</eg></fos:expression>
               <fos:result>xs:hexBinary("B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78")</fos:result>
            </fos:test>
            <fos:test use="v-hash-doc" spec="XQuery">
               <fos:expression><eg>hash($doc)</eg></fos:expression>
               <fos:result>xs:hexBinary("900150983CD24FB0D6963F7D28E17F72")</fos:result>
            </fos:test>
            <fos:test use="v-hash-doc" spec="XQuery">
               <fos:expression><eg>hash(serialize($doc), "sha-1") 
=> xs:base64Binary()   
=> string()</eg></fos:expression>
               <fos:result>"8PzN28NtxQv5RlxQ5/w6DcnrpEU="</fos:result>
            </fos:test>
            <fos:test use="v-hash-salt">
               <fos:expression><eg>hash("password123" || $salt, "SHA-256")</eg></fos:expression>
               <fos:result>xs:hexBinary("9C9B913EB1B6254F4737CE947EFD16F16E916F9D6EE5C1102A2002E48D4C88BD")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("", "CRC-32")</eg></fos:expression>
               <fos:result>xs:hexBinary("00000000")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>hash("input", "CRC-32")</eg></fos:expression>
               <fos:result>xs:hexBinary("D82832D7")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>hash("password123", "sha-unknown")</fos:expression>
               <fos:error-result error-code="FOHA0001"/>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="779 1188 1422 1426" PR="937 995 1190" date="2024-01-23"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="encode-for-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="encode-for-uri" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Encodes reserved characters in a string that is intended to be used in the path segment
            of a URI.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the zero-length
            string.</p>
         <p>This function applies the URI escaping rules defined in section 2 of <bibref
               ref="rfc3986"
               /> to the <code>xs:string</code> supplied as <code>$value</code>. The
            effect of the function is to escape reserved characters. Each such character in the
            string is replaced with its percent-encoded form as described in <bibref
               ref="rfc3986"/>.</p>
         <p>Since <bibref ref="rfc3986"
            /> recommends that, for consistency, URI producers and
            normalizers should use uppercase hexadecimal digits for all percent-encodings, this
            function must always generate hexadecimal values using the upper-case letters A-F.</p>
      </fos:rules>
      <fos:notes>
         <p>All characters are escaped except those identified as “unreserved” by <bibref
               ref="rfc3986"
            />, that is the upper- and lower-case letters <code>A</code> to <code>Z</code>,
            the digits <code>0</code> to <code>9</code>, HYPHEN-MINUS (<code>-</code>),
            LOW LINE (<code>_</code>), FULL STOP (<code>.</code>), and TILDE (<code>~</code>).</p>
         <p>This function escapes URI delimiters and therefore cannot be used indiscriminately to
            encode “invalid” characters in a path segment.</p>
         <p>This function is invertible but not idempotent. This is because a string containing a
            percent character will be modified by applying the function: for example
               <code>100%</code> becomes <code>100%25</code>, while <code>100%25</code> becomes
               <code>100%2525</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>encode-for-uri(
  "http://example.com/00/Weather/CA/Los%20Angeles#ocean"
)</eg></fos:expression>
               <fos:result>"http%3A%2F%2Fexample.com%2F00%2FWeather%2FCA%2FLos%2520Angeles%23ocean"</fos:result>
               <fos:postamble>This is probably not what the user intended because all of the
                  delimiters have been encoded.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>concat(
  "http://example.com/",
  encode-for-uri("~bébé")
)</eg></fos:expression>
               <fos:result>"http://example.com/~b%C3%A9b%C3%A9"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>concat(
  "http://example.com/",
  encode-for-uri("100% organic")
)</eg></fos:expression>
               <fos:result>"http://example.com/100%25%20organic"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="decode-from-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="decode-from-uri" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Decodes URI-escaped characters in a string.</p>
      </fos:summary>
      <fos:rules>
         <p>This function returns the original representation of a URI-escaped string.</p>
         <p>If <code>$value</code> is the empty sequence, the function returns the zero-length
            string.</p>
         <p>Otherwise, the value is first converted to a sequence of octets. Each plus sign
            (<code>+</code>) is replaced with the octet representing a space character
            (<code>x20</code>), and any substring that matches the regular expression
            <code>%[a-fA-F0-9][a-fA-F0-9]</code> is replaced with an octet for the two-digit
            hexadecimal number that follows the percent sign. Characters that are not part of
            such a substring are replaced with the octets of their UTF-8 encoding.
            For example, <code>"A%42+C"</code> results in the octets <code>x41</code>,
            <code>x42</code>, <code>x20</code>, <code>x43</code>, and <code>"💡"</code> yields
            <code>xF0</code>, <code>x9F</code>, <code>x92</code>, and <code>xA1</code>.</p>
         <p>If <code>%</code> is followed by up to two characters that are not hexadecimal digits,
            these characters are replaced by octets <code>xEF</code>, <code>xBF</code>,
            and <code>xBD</code>, that is, the UTF-8 encoding of the Unicode replacement character
            (<char>U+FFFD</char>). For example, the incomplete or invalid percent-encoded strings
            <code>"%"</code>, <code>"%X"</code>, <code>"%AX"</code>, and <code>"%XA"</code> are all
            replaced with these octets. For the string <code>"%1X!"</code>, the octets <code>xEF</code>,
            <code>xBF</code>, <code>xBD</code>, and <code>x21</code> are returned.</p>
         <p>Next, the resulting octets are interpreted as UTF-8. For example,
            <code>x41</code>, <code>x42</code>, <code>x20</code>, and <code>x43</code>
            becomes <code>"AB C"</code>, and <code>xF0</code>, <code>x9F</code>,
            <code>x92</code>, and <code>xA1</code> becomes <code>"💡"</code>.</p>
         <p>If an invalid UTF-8 octet sequence is encountered, the octets that have
            successfully been parsed are replaced with a Unicode replacement character.
            Examples:</p>
         <ulist>
            <item><p>The single octet <code>xF0</code> is converted to <code>"�"</code>.</p></item>
            <item><p>The octets <code>xF0</code>, <code>x9F</code>, <code>x92</code>, and
               <code>x41</code> are converted to <code>"�A"</code>:
               The bit pattern of the first octet indicates that the UTF-8 character comprises
               four octets. As the fourth octet is invalid, a Unicode replacement character is
               added for the first three octets, and the fourth (invalid) octet is parsed as a
               new character.</p></item>
            <item><p>Similarly, the octets <code>xF0</code>, <code>xF0</code>, <code>x9F</code>,
               <code>x92</code>, and <code>xA1</code> are converted to <code>"�💡"</code>:
               The second octet is invalid, but it becomes valid when being parsed as the
               first octet of the remaining UTF-8 sequence.</p></item>
         </ulist>
         <p>Similarly, a UTF-8 octet sequence that represents a codepoint that is not a
            valid XML character is replaced with a Unicode replacement character.
            For example, <code>x00</code> becomes <code>"�"</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>decode-from-uri("http://example.com/")</fos:expression>
               <fos:result>"http://example.com/"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>decode-from-uri("~b%C3%A9b%C3%A9?a=b+c")</fos:expression>
               <fos:result>"~bébé?a=b c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>decode-from-uri("%00-%XX-%F0%9F%92%41-%F0%F0%9F%92%A1")</fos:expression>
               <fos:result>"�-�-�A-�💡"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="600" PR="631" date="2023-09-12"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="iri-to-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="iri-to-uri" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Converts a string containing an IRI into a URI according to the rules of <bibref
               ref="rfc3987"/>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the zero-length
            string.</p>
         <p>Otherwise, the function converts <code>$value</code> into a URI according to
            the rules given in Section 3.1 of <bibref
               ref="rfc3987"
               /> by percent-encoding characters
            that are allowed in an IRI but not in a URI. If <code>$value</code> contains a character
            that is invalid in an IRI, such as the space character (see note below), the invalid
            character is replaced by its percent-encoded form as described in <bibref
               ref="rfc3986"/> before the conversion is performed.</p>
         <p>Since <bibref ref="rfc3986"
            /> recommends that, for consistency, URI producers and
            normalizers should use uppercase hexadecimal digits for all percent-encodings, this
            function must always generate hexadecimal values using the upper-case letters A-F.</p>
      </fos:rules>
      <fos:notes>
         <p>The function is idempotent but not invertible. Both the inputs <code>My Documents</code>
            and <code>My%20Documents</code> will be converted to the output
               <code>My%20Documents</code>.</p>
         <p>This function does not check whether <code>$iri</code> is a valid IRI. It treats it as
            an <termref
               def="string">string</termref> and operates on the <termref def="character"
               >characters</termref> in the string.</p>
         <!--Text replaced by erratum E8 change 1"-->
         <p> The following printable ASCII characters are invalid in an IRI: <code>&lt;</code>, <code>&gt;</code>,
            <code>"</code>, <code> </code>, <code>{</code>, <code>}</code>, <code>|</code>,
            <code>\</code>, <code>^</code>, and <code>`</code>. Since these
            characters should not appear in an IRI, if they do appear in <code>$iri</code> they will
            be percent-encoded. In addition, characters outside the range <char>U+0020</char> to <char>U+007E</char> will be
            percent-encoded because they are invalid in a URI. </p>
         <!--End of text replaced by erratum E8-->
         <p> Since this function does not escape the character <char>U+0025</char> and this character is not
            allowed in data within a URI, users wishing to convert character strings (such as file
            names) that include <code>%</code> to a URI should manually escape <code>%</code>
            by replacing it with <code>%25</code>.
         </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>iri-to-uri(
  "http://www.example.com/00/Weather/CA/Los%20Angeles#ocean"
)</eg></fos:expression>
               <fos:result>"http://www.example.com/00/Weather/CA/Los%20Angeles#ocean"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>iri-to-uri("http://www.example.com/~bébé")</fos:expression>
               <fos:result>"http://www.example.com/~b%C3%A9b%C3%A9"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="escape-html-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="escape-html-uri" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Escapes a URI in the same way that HTML user agents handle attribute values expected to
            contain URIs.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the zero-length
            string.</p>
         <p>Otherwise, the function escapes all <termref def="character"
               >characters</termref> except
            printable characters of the US-ASCII coded character set, specifically the <termref
               def="codepoint"
               >codepoints</termref> between 32 and 126 (decimal) inclusive. Each
            character in <code>$value</code> to be escaped is replaced by an escape sequence, which is
            formed by encoding the character as a sequence of octets in UTF-8, and then representing
            each of these octets in the form %HH, where HH is the hexadecimal representation of the
            octet. This function must always generate hexadecimal values using the upper-case
            letters A-F.</p>
      </fos:rules>
      <fos:notes>
         <p>The behavior of this function corresponds to the recommended handling of non-ASCII
            characters in URI attribute values as described in <bibref
               ref="HTML40"/> Appendix
            B.2.1.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>escape-html-uri(
  "http://www.example.com/00/Weather/CA/Los Angeles#ocean"
)</eg></fos:expression>
               <fos:result>"http://www.example.com/00/Weather/CA/Los Angeles#ocean"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>escape-html-uri(
  "javascript:if (navigator.browserLanguage == 'fr') window.open('http://www.example.com/~bébé');"
)</eg></fos:expression>
               <fos:result>"javascript:if (navigator.browserLanguage == 'fr') window.open('http://www.example.com/~b%C3%A9b%C3%A9');"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="contains" prefix="fn">
      <fos:signatures>
         <fos:proto name="contains" return-type="xs:boolean">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="substring" type="xs:string?"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the string <code>$value</code> contains <code>$substring</code> as a
            substring, taking collations into account.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> or <code>$substring</code> is the empty sequence, or
            contains only ignorable collation units, it is interpreted as the zero-length
            string.</p>
         <p>If <code>$substring</code> is the zero-length string, then the function returns
               <code>true</code>.</p>
         <p>If <code>$value</code> is the zero-length string, the function returns
               <code>false</code>.</p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>
         <p>The function returns an <code>xs:boolean</code> indicating whether or not 
               <code>$value</code> contains (at the beginning, at the end, or anywhere within) at
            least one sequence of collation units that provides a <termref def="dt-minimal-match.collation"/> to the
            collation units in <code>$substring</code>, according to the collation that is
            used.</p>


      </fos:rules>
      <fos:errors>
         <p>A <phrase>dynamic</phrase> error <rfc2119>may</rfc2119> be raised <errorref class="CH"
               code="0004"/> if the specified collation does not support collation units.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>The collation used in some of these examples, <code>$coll</code>, is a
               collation in which both <code>-</code> and <code>*</code> are ignorable collation units.</p>
            <p>“Ignorable collation unit” is equivalent to “ignorable collation element” in <bibref
                  ref="UNICODE-TR10"/>.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>contains("tattoo", "t")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>contains("tattoo", "ttt")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>contains("", ())</fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>The first rule is applied, followed by the second
                  rule.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:variable name="coll" id="v-contains-coll" as="xs:string">
"http://www.w3.org/2013/collation/UCA?lang=en;alternate=blanked;strength=primary"</fos:variable>
         <fos:example>
            <fos:test use="v-contains-coll">
               <fos:expression><eg>contains(
  "abcdefghi",
  "-d-e-f-",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-contains-coll">
               <fos:expression><eg>contains(
  "a*b*c*d*e*f*g*h*i*",
  "d-ef-",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-contains-coll">
               <fos:expression><eg>contains(
  "abcd***e---f*--*ghi",
  "def",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-contains-coll">
               <fos:expression><eg>contains(
  (),
  "--***-*---",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>The second argument contains only ignorable collation units and is
                  equivalent to the zero-length string.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="starts-with" prefix="fn">
      <fos:signatures>
         <fos:proto name="starts-with" return-type="xs:boolean">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="substring" type="xs:string?"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the string <code>$value</code> contains <code>$substring</code> as a leading
            substring, taking collations into account.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> or <code>$substring</code> is the empty sequence, or
            contains only ignorable collation units, it is interpreted as the zero-length
            string.</p>
         <p>If <code>$substring</code> is the zero-length string, then the function returns
               <code>true</code>. If <code>$value</code> is the zero-length string and
            <code>$substring</code> is not the zero-length string, then the function returns
               <code>false</code>.</p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>
         <p>The function returns an <code>xs:boolean</code> indicating whether or not 
               <code>$value</code> starts with a sequence of collation units that provides a
               <termref def="dt-match.collation"/> to the collation units of <code>$substring</code> according to the
            collation that is used.</p>
         

      </fos:rules>
      <fos:errors>
         <p>A <phrase>dynamic</phrase> error <rfc2119>may</rfc2119> be raised <errorref class="CH"
               code="0004"/> if the specified collation does not support collation units.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>The collation used in some of these examples, <code>$coll</code>, is a
               collation in which both <code>-</code> and <code>*</code> are ignorable collation units.</p>
            <p>“Ignorable collation unit” is equivalent to “ignorable collation element” in <bibref
                  ref="UNICODE-TR10"/>.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>starts-with("tattoo", "tat")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>starts-with("tattoo", "att")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>starts-with((), ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:variable name="coll" id="v-starts-with-coll" as="xs:string">
"http://www.w3.org/2013/collation/UCA?lang=en;alternate=blanked;strength=primary"</fos:variable>
         <fos:example>
            <fos:test use="v-starts-with-coll">
               <fos:expression><eg>starts-with(
  "abcdefghi",
  "-a-b-c-",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-starts-with-coll">
               <fos:expression><eg>starts-with(
  "a*b*c*d*e*f*g*h*i*",
  "a-bc-",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-starts-with-coll">
               <fos:expression><eg>starts-with(
  "abcd***e---f*--*ghi",
  "abcdef",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-starts-with-coll">
               <fos:expression><eg>starts-with(
  (),
  "--***-*---",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>The second argument contains only ignorable collation units and is
                  equivalent to the zero-length string.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-starts-with-coll">
               <fos:expression><eg>starts-with(
  "-abcdefghi",
  "-abc",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="ends-with" prefix="fn">
      <fos:signatures>
         <fos:proto name="ends-with" return-type="xs:boolean">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="substring" type="xs:string?"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the string <code>$value</code> contains <code>$substring</code> as a trailing
            substring, taking collations into account.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> or <code>$substring</code> is the empty sequence, or
            contains only ignorable collation units, it is interpreted as the zero-length
            string.</p>
         <p>If <code>$substring</code> is the zero-length string, then the function returns
               <code>true</code>. If <code>$value</code> is the zero-length string and
            the value of <code>$substring</code> is not the zero-length string, then the function returns
               <code>false</code>.</p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>
         <p>The function returns an <code>xs:boolean</code> indicating whether or not 
               <code>$value</code> ends with a sequence of collation units that provides a
               <termref def="dt-match.collation"/> to the collation units of <code>$substring</code> according to the
            collation that is used.</p>
         

      </fos:rules>
      <fos:errors>
         <p>A <phrase>dynamic</phrase> error <rfc2119>may</rfc2119> be raised <errorref class="CH"
               code="0004"/> if the specified collation does not support collation units.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>The collation used in some of these examples, <code>$coll</code>, is a
               collation in which both <code>-</code> and <code>*</code> are ignorable collation units.</p>
            <p>“Ignorable collation unit” is equivalent to “ignorable collation element” in <bibref
                  ref="UNICODE-TR10"/>.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>ends-with("tattoo", "tattoo")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>ends-with("tattoo", "atto")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>ends-with((), ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:variable name="coll" id="v-ends-with-coll" as="xs:string">
"http://www.w3.org/2013/collation/UCA?lang=en;alternate=blanked;strength=primary"</fos:variable>
         <fos:example>
            <fos:test use="v-ends-with-coll">
               <fos:expression><eg>ends-with(
  "abcdefghi",
  "-g-h-i-",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-ends-with-coll">
               <fos:expression><eg>ends-with(
  "abcd***e---f*--*ghi",
  "defghi",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-ends-with-coll">
               <fos:expression><eg>ends-with(
  "abcd***e---f*--*ghi",
  "defghi",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-ends-with-coll">
               <fos:expression><eg>ends-with(
  (),
  "--***-*---",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>The second argument contains only ignorable collation units and is
                  equivalent to the zero-length string.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-ends-with-coll">
               <fos:expression><eg>ends-with(
  "abcdefghi",
  "ghi-",
  $coll
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="substring-before" prefix="fn">
      <fos:signatures>
         <fos:proto name="substring-before" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="substring" type="xs:string?"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the part of <code>$value</code> that precedes the first occurrence of
               <code>$substring</code>, taking collations into account.</p>
      </fos:summary>
      <fos:rules>
         <p> If <code>$value</code> or <code>$substring</code> is the empty sequence, or
            contains only ignorable collation units, it is interpreted as the zero-length
            string.</p>
         <p>If <code>$substring</code> is the zero-length string, then the function returns
            the zero-length string. </p>
         <p>If <code>$value</code> does not contain a string that is equal to 
            <code>$substring</code>, then the function returns the zero-length string. </p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>
         <p>The function returns the substring of <code>$value</code> that precedes in
            <code>$value</code> the first occurrence of a sequence of collation units
            that provides a <termref def="dt-minimal-match.collation"/> to the collation units of <code>$substring</code>
            according to the collation that is used.</p>
 

      </fos:rules>
      <fos:errors>
         <p>A <phrase>dynamic</phrase> error <rfc2119>may</rfc2119> be raised <errorref class="CH"
               code="0004"/> if the specified collation does not support collation units.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>The collation used in some of these examples, <code>$coll</code>, is a
               collation in which both <code>-</code> and <code>*</code> are ignorable collation units.</p>
            <p>“Ignorable collation unit” is equivalent to “ignorable collation element” in <bibref
                  ref="UNICODE-TR10"/>.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring-before("tattoo", "attoo")</fos:expression>
               <fos:result>"t"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring-before("tattoo", "tatto")</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring-before((), ())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
         <fos:variable name="coll" id="v-substring-before-coll" as="xs:string">
"http://www.w3.org/2013/collation/UCA?lang=en;alternate=blanked;strength=primary"</fos:variable>
         <fos:example>
            <fos:test use="v-substring-before-coll">
               <fos:expression><eg>substring-before(
  "abcdefghi",
  "--d-e-",
  $coll
)</eg></fos:expression>
               <fos:result>"abc"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-substring-before-coll">
               <fos:expression><eg>substring-before(
  "abc--d-e-fghi",
  "--d-e-",
  $coll
)</eg></fos:expression>
               <fos:result>"abc--"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-substring-before-coll">
               <fos:expression><eg>substring-before(
  "a*b*c*d*e*f*g*h*i*",
  "***cde",
  $coll
)</eg></fos:expression>
               <fos:result>"a*b*"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-substring-before-coll">
               <fos:expression><eg>substring-before(
  "Eureka!",
  "--***-*---",
  $coll
)</eg></fos:expression>
               <fos:result>""</fos:result>
               <fos:postamble>The second argument contains only ignorable collation units and is
                  equivalent to the zero-length string.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="substring-after" prefix="fn">
      <fos:signatures>
         <fos:proto name="substring-after" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="substring" type="xs:string?"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the part of <code>$value</code> that follows the first occurrence of
               <code>$substring</code>, taking collations into account.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> or <code>$substring</code> is the empty sequence, or
            contains only ignorable collation units, it is interpreted as the zero-length
            string.</p>
         <p>If <code>$substring</code> is the zero-length string, then the function returns
            the value of <code>$value</code>.</p>
         <p>If <code>$value</code> does not contain a string that is equal to 
            <code>$substring</code>, then the function returns the zero-length string. </p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>
         <p>The function returns the substring of <code>$value</code> that follows in
             <code>$value</code> the first occurrence of a sequence of collation units
            that provides a <termref def="dt-minimal-match.collation"/> to the collation units of <code>$substring</code>
            according to the collation that is used. </p>


      </fos:rules>
      <fos:errors>
         <p>A dynamic error <rfc2119>may</rfc2119> be raised <errorref class="CH" code="0004"
            /> if
            the specified collation does not support collation units.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>The collation used in some of these examples, <code>$coll</code>, is a
               collation in which both <code>-</code> and <code>*</code> are ignorable collation units.</p>
            <p>“Ignorable collation unit” is equivalent to “ignorable collation element” in <bibref
                  ref="UNICODE-TR10"/>.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring-after("tattoo", "tat")</fos:expression>
               <fos:result>"too"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring-after("tattoo", "tattoo")</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>substring-after((), ())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
         </fos:example>
         <fos:variable name="coll" id="v-substring-after-coll" as="xs:string">
"http://www.w3.org/2013/collation/UCA?lang=en;alternate=blanked;strength=primary"</fos:variable>
         <fos:example>
            <fos:test use="v-substring-after-coll">
               <fos:expression><eg>substring-after(
  "abcdefghi",
  "--d-e-",
  $coll
)</eg></fos:expression>
               <fos:result>"fghi"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-substring-after-coll">
               <fos:expression><eg>substring-after(
  "abc--d-e-fghi",
  "--d-e-",
  $coll
)</eg></fos:expression>
               <fos:result>"-fghi"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-substring-after-coll">
               <fos:expression><eg>substring-after(
  "a*b*c*d*e*f*g*h*i*",
  "***cde***",
  $coll
)</eg></fos:expression>
               <fos:result>"*f*g*h*i*"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-substring-after-coll">
               <fos:expression><eg>substring-after(
  "Eureka!",
  "--***-*---",
  $coll
)</eg></fos:expression>
               <fos:result>"Eureka!"</fos:result>
               <fos:postamble>The second argument contains only ignorable collation units and is
                  equivalent to the zero-length string.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="matches" prefix="fn">
      <fos:signatures>
         <fos:proto name="matches" return-type="xs:boolean">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="pattern" type="xs:string"/>
            <fos:arg name="flags" type="xs:string?" default='""' note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the supplied string matches a given regular expression.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, it is interpreted as the zero-length
            string.</p>
         <p>Flags are defined in <specref ref="flags"/>.</p>
         <p>The function returns <code>true</code> if the set of <termref def="dt-disjoint-matching-segments"/> obtained
            by matching <code>$value</code> against the regular expression <code>$pattern</code>,
            with the associated <code>$flags</code>, is non-empty. Otherwise, the function returns <code>false</code>.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RX" code="0002"
               /> if 
               <code>$pattern</code> is invalid according to the rules described in <specref
               ref="regex-syntax"/>. </p>
         <p>A dynamic error is raised <errorref class="RX" code="0001"
               /> if 
               <code>$flags</code> is invalid according to the rules described in <specref
               ref="flags"/>. </p>
      </fos:errors>
      <fos:notes>
         <p>Unless the metacharacters <code>^</code> and <code>$</code> are used as anchors, the
            string is considered to match the pattern if any substring matches the pattern. But if
            anchors are used, the anchors must match the start/end of the string (in string mode),
            or the start/end of a line (in multi-line mode). </p>
         <p>This is different from the behavior of patterns in <bibref ref="xmlschema-2"
               />, where
            regular expressions are <emph>implicitly</emph> anchored.</p>
         <p>Regular expression matching is defined on the basis of Unicode codepoints; it takes no
            account of collations.</p>
         <p>It is valid for the regular expression to match a zero-length segment of <code>$value</code>.
         For example, the result of the expression <code>matches($s, "")</code> is always true, regardless
         of the value of <code>$s</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>matches("abracadabra", "bra")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>matches("abracadabra", "^a.*a$")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>matches("abracadabra", "^bra")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
 
         <fos:variable name="poem" id="v-matches-poem" as="element()"><![CDATA[<poem author="Wilhelm Busch">
Kaum hat dies der Hahn gesehen,
Fängt er auch schon an zu krähen:
Kikeriki! Kikikerikih!!
Tak, tak, tak! - da kommen sie.
</poem>]]></fos:variable>
         <fos:example>
            <fos:test use="v-matches-poem" spec="XQuery">
               <fos:expression>matches($poem, "Kaum.*krähen")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-matches-poem" spec="XQuery">
               <fos:expression>matches($poem, "Kaum.*krähen", "s")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-matches-poem" spec="XQuery">
               <fos:expression>matches($poem, "^Kaum.*gesehen,$", "m")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-matches-poem" spec="XQuery">
               <fos:expression>matches($poem, "^Kaum.*gesehen,$")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-matches-poem" spec="XQuery">
               <fos:expression>matches($poem, "kiki", "i")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="replace" prefix="fn">
      <fos:signatures>
         <fos:proto name="replace" return-type="xs:string">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="pattern" type="xs:string"/>
            <fos:arg name="replacement" type="(xs:string | fn(xs:untypedAtomic, xs:untypedAtomic*) as item()?)?" default='""' note="default-on-empty"/>
            <fos:arg name="flags" type="xs:string?" default='""' note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string produced from the input string by replacing any segments that match a
            given regular expression with a supplied replacement string,
            provided either literally, or by invoking a supplied function.</p>
      </fos:summary>
      <fos:rules>
         <p>If the <code>$flags</code> argument is omitted or if it is the empty sequence,
            the effect is the same as setting <code>$flags</code> to a zero-length string.
            Flags are defined in <specref ref="flags"/>.</p>
         <p>The string <code>$value</code> is matched against the regular expression <code>$pattern</code>,
            using the supplied <code>$flags</code>, to obtain a set of <termref def="dt-disjoint-matching-segments"/>.
            A replacement string <var>R</var> for each 
            of these segments (say <var>M</var>) is determined by the value of the
            <code>$replacement</code> argument, by applying the first
         of the following rules that applies:</p>
         <ulist>
            <item><p>If <code>$replacement</code> is a function item <var>F</var>, then
               <var>R</var> is obtained by calling <var>F</var>, and then applying the
               function <function>fn:string</function> to the result.</p>
               <p>The first argument to <var>F</var> is the string to be replaced,
                  provided as <code>xs:untypedAtomic</code>.</p>
               <p>The second argument to <var>F</var> provides the captured
                  groups as an <code>xs:untypedAtomic</code> sequence.
                  The <code>Nth</code> item in this sequence is the string value of the segment captured by 
                  the <code>Nth</code> capturing subexpression. If the
                  <code>Nth</code> capturing subexpression was not matched, the <code>Nth</code> item
                  will be the zero-length string.</p>
               <p>Note that the rules for function coercion mean that the function actually
                  supplied for <var>F</var> may be an arity-1 function: the
                  second argument does not need to be declared if it is not used.</p>
            </item>
            
            <item><p>If <code>$replacement</code> is a string and the 
               <code>q</code> flag is present, <var>R</var> is the value
            of <code>$replacement</code>.</p></item>           
            <item>
               <p>Otherwise, the value of <code>$replacement</code> is processed as follows.</p>
            <p>Within the supplied <code>$replacement</code> string, a variable marker <code>$<var>N</var></code> (where 
               <var>N</var> is an unsigned integer) may
            be used to refer to the <var>N</var>th captured group associated with <var>M</var>.
               The replacement string <var>R</var> is obtained by replacing each of these variable markers
            with the string value of the relevant captured group.
               The variable marker <code>$0</code> refers to the substring captured by the regular expression as a
            whole.</p>
               <p>A literal <code>$</code> character within the
            replacement string must be written as <code>\$</code>, and a literal <code>\</code>
            character must be written as <code>\\</code>.</p>
         <p>More specifically, the rules are as follows, where <var>S</var> is the number of
            capturing subexpressions in the regular expression, and <var>N</var> is the
            decimal number formed by taking all the digits that consecutively follow the
               <code>$</code> character in <code>$replacement</code>:</p>

         <olist>
            <item>
               <p>If <var>N</var>=<code>0</code>, then the variable is replaced by the string value of <var>M</var>.</p>
            </item>
            <item>
               <p>If <code>1</code>&lt;=<var>N</var>&lt;=<var>S</var>, then the variable marker is
                  replaced by the string value of the <var>N</var>th captured group associated
                  with <var>M</var>. If the
                     <var>N</var>th parenthesized sub-expression was not matched, then the
                  variable marker is replaced by the zero-length string.</p>
            </item>
            <item>
               <p>If <var>S</var>&lt;<var>N</var>&lt;=<code>9</code>, then the variable marker is
                  replaced by the zero-length string.</p>
            </item>
            <item>
               <p>Otherwise (if <var>N</var>&gt;<var>S</var> and
                     <var>N</var>&gt;<code>9</code>), the last digit of <var>N</var> is taken to
                  be a literal character to be included “as is” in the replacement string, and the
                  rules are reapplied using the number <var>N</var> formed by stripping off this
                  last digit.</p>
               
               <p>For example, if the replacement string is 
               <code>"$23"</code>
             and there are 5 substrings, the result contains the value of the substring that
            matches the second capturing subexpression, followed by the digit 
               <code>3</code>.</p>
            </item>
         </olist>

         
            
            
            
            </item>

         </ulist>
         
         <p>The function returns the <code>xs:string</code> that is obtained by replacing each
            of the <termref def="dt-disjoint-matching-segments"/> of <code>$value</code> with 
            the corresponding value of <var>R</var>.</p>
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RX" code="0002"
               /> if the value of
               <code>$pattern</code> is invalid according to the rules described in section <specref
               ref="regex-syntax"/>. </p>
         <p>A dynamic error is raised <errorref class="RX" code="0001"
               /> if the value of
               <code>$flags</code> is invalid according to the rules described in section <specref
               ref="flags"/>. </p>
         <!--<p>A dynamic error is raised <errorref class="RX" code="0003"
               /> if the pattern matches a
            zero-length string, that is, if the expression <code>fn:matches("", $pattern,
               $flags)</code> returns <code>true</code>. It is not an error, however, if a captured
            substring is zero-length.</p>-->
         <p>In the absence of the <code>q</code> flag,
            a dynamic error is raised <errorref
               class="RX" code="0004"
               /> if the value of
               <code>$replacement</code> contains a dollar sign (<code>$</code>) character that is not
            immediately followed by a digit <code>0-9</code> and not immediately preceded by a
            backslash (<code>\</code>).</p>
         <p>In the absence of the <code>q</code> flag,
            a dynamic error is raised <errorref
               class="RX" code="0004"
               /> if the value of
               <code>$replacement</code> contains a backslash (<code>\</code>) character that is not part of a
               <code>\\</code> pair, unless it is immediately followed by a dollar sign (<code>$</code>)
            character.</p>
         <p>A dynamic error is raised <errorref class="RX" code="0005"/> if both the <code>$replacement</code> 
            and <code>$action</code> arguments are supplied, and neither is the empty sequence.</p>
      </fos:errors>
      <fos:notes>
         <p>If the input string contains no substring that matches the regular
            expression, the result of the function is a single string identical to the input
            string.</p>
         <p>If two overlapping substrings of <code>$value</code> both match the
            <code>$pattern</code>, then only the first one (that is, the one whose first <termref
            def="character">character</termref> comes first in the <code>$value</code> string) is
            replaced.</p>
         <p> If two alternatives within the pattern both match at the same position in the
               <code>$input</code>, then the match that is chosen is the one matched by the first
            alternative. For example:</p>
         <eg xml:space="preserve"> replace("abcd", "(ab)|(a)", "[1=$1][2=$2]") returns "[1=ab][2=]cd"</eg>
         <p>The rules for <termref def="dt-disjoint-matching-segments"/> allow a zero-length matching
            segment to immediately follow a non-zero-length matching segment (they are not considered to
            overlap). This means, for example, that the regular expression <code>.*</code>
         will typically produce two matches: one matching segment containing all the characters in the 
         input string, and a second zero-length matching seqment at the end position of the string.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>replace("abracadabra", "bra", "*")</fos:expression>
               <fos:result>"a*cada*"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("abracadabra", "a.*a", "*")</fos:expression>
               <fos:result>"*"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("abracadabra", "a.*?a", "*")</fos:expression>
               <fos:result>"*c*bra"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("abracadabra", "a", "")</fos:expression>
               <fos:result>"brcdbr"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("abracadabra", "a(.)", "a$1$1")</fos:expression>
               <fos:result>"abbraccaddabbra"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("AAAA", "A+", "b")</fos:expression>
               <fos:result>"b"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("AAAA", "A+?", "b")</fos:expression>
               <fos:result>"bbbb"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("In the beginning was the Word", "\b", "|")</fos:expression>
               <fos:result>"|In| |the| |beginning| |was| |the| |Word|"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("abcd!", "[a-z](?=.*(.)$)", "$0$1")</fos:expression>
               <fos:result>"a!b!c!d!!"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>replace("darted", "^(.*?)d(.*)$", "$1c$2")</fos:expression>
               <fos:result>"carted"</fos:result>
               <fos:postamble>Only the first <code>d</code> is replaced.</fos:postamble>
            </fos:test>
            <fos:test diff="add" at="A">
               <fos:expression><eg>replace("abracadabra", "bra", upper-case#1)</eg></fos:expression>
               <fos:result>"aBRAcadaBRA"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>replace("Chapter 9", "[0-9]+", fn { . + 1 })</eg></fos:expression>
               <fos:result>"Chapter 10"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>replace(
  "LHR to LAX",
  "\b[A-Z]{3}\b",
  { 'LAX': 'Los Angeles', 'LHR': 'London' }
)</eg></fos:expression>
               <fos:result>"London to Los Angeles"</fos:result>
            </fos:test>
            <fos:test diff="add" at="A">
               <fos:expression><eg>replace(
  "57°43′30″",
  "([0-9]+)°([0-9]+)′([0-9]+)″",
  fn($s, $groups) {
    string($groups[1] + $groups[2] ÷ 60 + $groups[3] ÷ 3600) || '°'
  }
)</eg></fos:expression>
               <fos:result>"57.725°"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1876" PR="1897" date="2025-04-08"><p>The <code>$replacement</code> argument can now be a function
            that computes the replacement strings.</p></fos:change>
         <fos:change issue="1911" PR="1913" date="2025-04-08"><p>It is now permitted for the regular expression to match a zero-length string.</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="tokenize" prefix="fn">
      <fos:signatures>
         <fos:proto name="tokenize" return-type="xs:string*">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="pattern" type="xs:string?" default='()'/>
            <fos:arg name="flags" type="xs:string?" default='""' note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence of strings constructed by splitting the input wherever a separator is
            found; the separator is any substring that matches a given regular expression.</p>
      </fos:summary>
      <fos:rules>
         <p diff="add" at="2023-01-17">The following rules apply when the <code>$pattern</code>
            argument is the empty sequence:</p>
         <ulist>
            <item><p>The function splits the supplied string at whitespace boundaries.</p></item>
            <item><p>More specifically, calling <code>fn:tokenize($value)</code> <phrase diff="add" at="2023-01-17">or <code>fn:tokenize($value, ())</code></phrase>
               is equivalent to calling <code>fn:tokenize(fn:normalize-space($value), ' '))</code> where the second argument
               is a single space character (x20).</p></item>
            <item><p>The <code>$flags</code> argument is ignored.</p></item>
         </ulist>
         <p>The following rules apply when the <code>$pattern</code> argument is supplied as a single string:</p>
         <ulist>
            <item><p>Flags are defined in <specref ref="flags"/>.</p></item>
            <item><p>If <code>$value</code> is the empty sequence, or if <code>$value</code> is the
               zero-length string, the function returns the empty sequence.</p></item>
            <item>
               <p>The function returns a sequence of strings formed by breaking the <code>$value</code>
                  string into a sequence of strings, treating any substring that matches
                  <code>$pattern</code> as a separator. The separators themselves are not returned.</p>
            </item>
            <item><p>More specifically:</p>
               <ulist>
                  <item><p>Let <var>M0</var> be the sequence of <termref def="dt-disjoint-matching-segments"/>
            that results from matching <code>$value</code> against <code>$pattern</code> in the presence
            of <code>$flags</code>.</p></item>
                  <item><p>Unless the first segment in <var>M0</var> is zero-length and starts at the first <termref def="dt-character-position"/>
                  of <code>$value</code>, prepend a zero-length segment that starts at the start of <code>$value</code>:
                  call the result <var>M1</var>.</p></item>
                  <item><p>Unless the last segment in <var>M1</var> is zero-length and starts at the last <termref def="dt-character-position"/>
                  of <code>$value</code> (that is, the character position after the last character), append a zero-length 
                     segment that starts at the last character position of <code>$value</code>. Call the result <var>M2</var>.</p></item>
                  <item><p>For each pair of adjacent segments in <var>M2</var> (say, <var>S/n</var> and <var>S/n+1</var>),
                  construct a string (possibly zero-length) that is the substring of <code>$value</code> containing all characters 
                  that follow <var>S/n</var> and that precede <var>S/n+1</var>. Return this sequence of strings, in order.</p></item>
               </ulist>
            </item>
            
         </ulist>

      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RX" code="0002"
               /> if the value of
               <code>$pattern</code> is invalid according to the rules described in section <specref
               ref="regex-syntax"/>.</p>
         <p>A dynamic error is raised <errorref class="RX" code="0001"
               /> if the value of
               <code>$flags</code> is invalid according to the rules described in section <specref
               ref="flags"/>.</p>
         <!--<p>A dynamic error is raised <errorref class="RX" code="0003"
               /> if the supplied
               <code>$pattern</code> matches a zero-length string, that is, if <code>fn:matches("",
               $pattern, $flags)</code> returns <code>true</code>. </p>-->

      </fos:errors>
      <fos:notes>
         <p>If the input string is not zero length, and no separators are found in
            the input string, the result of the function is a single string identical to the input
            string.</p>
         <p>For the one-argument form of the function:</p>
         <ulist>
            <item><p>The function has a similar effect to
               the two-argument form with <code>\s+</code> as the separator pattern, except that the one-argument
               form strips leading and trailing whitespace, whereas the two-argument form delivers an extra
               zero-length token if leading or trailing whitespace is present.</p></item>
            <item><p>The separator used is any sequence
            of tab (<char>U+0009</char>), newline (<char>U+000A</char>), carriage return
            (<char>U+000D</char>) or space (<char>U+0020</char>) characters. This is the same as the
               separator recognized by list-valued attributes as defined in XSD.
               It is not the same as the separator recognized by list-valued attributes in HTML5,
               which also treats form-feed (<char>U+000C</char>) as whitespace. If it is necessary
               to treat form-feed as a separator, an explicit separator pattern should be used.</p></item>
         </ulist>
         <p>For the two-argument form of the function:</p>
         <ulist>
            <item><p>The function returns no information about the separators that were found
         in the string. If this information is required, the <function>fn:analyze-string</function> function
         can be used instead. Alternatively, zero-width assertions can be used to identify separators.
         For example, using the regular expression <code>(?&lt;=,)</code> will start a new token after every comma,
         including the comma as part of the previous token.</p></item>
            <item><p>If a separator occurs at the start of <code>$value</code>, and is not zero-length, the result
                  sequence will start with a zero-length string. Similarly, zero-length strings will also occur in
                  the result sequence if a non-zero-length separator occurs at the end of <code>$value</code>,
                  or if two adjacent substrings match the supplied <code>$pattern</code>.</p></item>
            <item><p>If two alternatives within the supplied <code>$pattern</code> both match at the same
                  position in the <code>$value</code> string, then the match that is chosen is the first.
                  For example:</p>
               <eg xml:space="preserve"> tokenize("abracadabra", "(ab)|(a)") returns ("", "r", "c", "d", "r", "")</eg></item>
            <item><p>The pattern may match zero-length segments of the input string. For example, the 
                 expression <code>tokenize("Do not eat", "\b")</code> returns the sequence 
               <code>"Do", " ", "not", " ", "eat"</code>.</p></item>
            <item><p>A string may be split into individual characters (producing the same effect as the
               <function>fn:characters</function> function) by using the empty regular expression 
               (for example, <code>tokenize("xyz", "")</code>,
               or any other regular expression such as <code>.??</code> that matches every zero-length string, regardless
               of position.</p>
                  <p>Unlike the <code>split</code> method in some other popular languages, however,
                  not every regular expression that matches a zero-length string produces this
                  behavior: for example the regular expression <code>\b</code> splits the string
                  before and after every word.</p></item>
         </ulist>
         
         
         

               
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>tokenize(" red green blue ")</fos:expression>
               <fos:result>"red", "green", "blue"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tokenize("The cat sat on the mat", "\s+")</fos:expression>
               <fos:result>"The", "cat", "sat", "on", "the", "mat"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tokenize(" red green blue ", "\s+")</fos:expression>
               <fos:result>"", "red", "green", "blue", ""</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tokenize("1, 15, 24, 50", ",\s*")</fos:expression>
               <fos:result>"1", "15", "24", "50"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tokenize("1,15,,24,50,", ",")</fos:expression>
               <fos:result>"1", "15", "", "24", "50", ""</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>fn:tokenize("the end", "\b")</fos:expression>
               <fos:result>"the", " ", "end"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>fn:tokenize("California", "")</fos:expression>
               <fos:result>"C", "a", "l", "i", "f", "o", "r", "n", "i", "a"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>tokenize(
  "Some unparsed &lt;br&gt; HTML &lt;BR&gt; text",
  "\s*&lt;br&gt;\s*", "i"
)</eg></fos:expression>
               <fos:result>"Some unparsed", "HTML", "text"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The second argument can now be the empty sequence.</p>
         </fos:change>
         <fos:change issue="1911" PR="1913" date="2025-04-08">
            <p>It is now permitted for the regular expression to match a zero-length string.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="analyze-string" prefix="fn">
      <fos:signatures>
         <fos:proto name="analyze-string" return-type="element(fn:analyze-string-result)">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="pattern" type="xs:string"/>
            <fos:arg name="flags" type="xs:string?" default='""' note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Analyzes a string using a regular expression, returning an XML structure that identifies
            which parts of the input string matched or failed to match the regular expression, and
            in the case of matched substrings, which substrings matched each capturing group in the
            regular expression.</p>
      </fos:summary>
      <fos:rules>
         <p>Flags are defined in <specref ref="flags"/>.</p>
         <p>If <code>$value</code> is the empty sequence, the function behaves as if
            <code>$value</code> were the zero-length string.</p>
         <p>The function returns an element node whose local name is
               <code>analyze-string-result</code>. This element and all its descendant elements have
            the namespace URI <code>http://www.w3.org/2005/xpath-functions</code>. The namespace
            prefix is <termref
               def="implementation-dependent"
               >implementation-dependent</termref>. The children of this element are a
            sequence of <code>fn:match</code> and <code>fn:non-match</code> elements. This sequence
            is formed by breaking the <code>$value</code> string into a sequence of strings,
            returning any substring that matches <code>$pattern</code> as the content of an
               <code>fn:match</code> element, and any intervening substring as the content of an
               <code>fn:non-match</code> element.</p>
         <p>More specifically, the function starts by matching the regular expression against the string,
            using the supplied <code>$flags</code>, to obtain the <termref def="dt-disjoint-matching-segments"/>.
            For each such segment it constructs an <code role="element-name">fn:match</code> child, whose string value is
            the string value of the segment. Before, between, or after these <code role="element-name">fn:match</code>
            elements, as required to ensure that the string value of the <code role="element-name">fn:analyze-string-result</code>
            element is the same as <code>$value</code>, it inserts <code role="element-name">fn:non-match</code> elements.
            The content of an <code role="element-name">fn:non-match</code> element is always a single (non-empty) text node,
            and two <code role="element-name">fn:non-match</code> elements never appear as adjacent siblings.</p>  
            
            
         
         <p>The captured groups for each <termref def="dt-disjoint-matching-segments">disjoint matching segment</termref>
            are represented using <code role="element-name">fn:group</code> or <code role="element-name">fn:lookahead-group</code>
            children of the corresponding <code role="element-name">fn:match</code> element. Groups captured by a subexpression within
         a lookahead assertion are referred to as lookahead groups; those not within a lookahead
         assertion are called ordinary groups.</p>

         <p>The content of an <code role="element-name">fn:match</code> element is in general:</p>
         
         <ulist>
            <item><p>A sequence of text nodes and <code role="element-name">fn:group</code> element children,
            whose string-values when concatenated comprise the string value of the matching segment,
            followed by</p></item>
            <item><p>A sequence of zero or more <code role="element-name">fn:lookahead-group</code> elements, 
            representing the lookahead groups</p></item>
         </ulist>
         
         <p>The string value of an <code role="element-name">fn:match</code> element may be empty.</p>
         
         <p>An <code role="element-name">fn:group</code> element
            with a <code>nr</code> attribute having the integer value <var>N</var> identifies 
            the substring captured by an ordinary group, specifically the string value of the <var>Nth</var> captured group. 
            For each ordinary capturing subexpression there will be at most one corresponding
               <code role="element-name">fn:group</code> element in each <code>fn:match</code> element in the
            result.</p>
         
         <p>By contrast, lookahead groups are represented by <code role="element-name">fn:lookahead-group</code> elements,
         which (if they appear at all) must follow all text node and <code role="element-name">fn:group</code> element children
         of the <code role="element-name">fn:match</code> element. These groups may overlap the matching and non-matching substrings, and
         indeed may overlap each other. They must appear in ascending numerical order of group number.
         The attributes of the <code role="element-name">fn:lookahead-group</code> element are as follows:</p>
         
         <ulist>
            <item><p><code>nr</code>: the group number, based on the position of the capturing subexpression
            that captured the group;</p></item>
            <item><p><code>value</code>: the string value of the segment that was captured;</p></item>
            <item><p><code>position</code>: the one-based start position of the segment within the input string.</p></item>
         </ulist>

         <p>If the function is called twice with the same arguments, it is <termref
               def="implementation-dependent"
               >implementation-dependent</termref> whether the two calls return the same element node
            or distinct (but deep equal) element nodes. In this respect it is <termref
               def="dt-nondeterministic">nondeterministic with respect to node identity</termref>.</p>

         <p>The base URI of the element nodes in the result is <termref
               def="implementation-dependent">implementation-dependent</termref>.</p>

         <p>A schema is defined for the structure of the returned element: see <specref
               ref="schema-for-analyze-string"/>.</p>

         <p>The result of the function will always be such that validation against this schema would succeed.
         However, it is <termref
               def="implementation-defined"
            >implementation-defined</termref> whether the result is typed or untyped,
         that is, whether the elements and attributes in the returned tree have type annotations that reflect
         the result of validating against this schema.</p>

      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RX" code="0002"
               /> if the value of
               <code>$pattern</code> is invalid according to the rules described in section <specref
               ref="regex-syntax"/>.</p>
         <p>A dynamic error is raised <errorref class="RX" code="0001"
               /> if the value of
               <code>$flags</code> is invalid according to the rules described in section <specref
               ref="flags"/>.</p>
         <!--<p>A dynamic error is raised <errorref class="RX" code="0003"
               /> if the supplied
               <code>$pattern</code> matches a zero-length string, that is, if <code>fn:matches("",
               $pattern, $flags)</code> returns <code>true</code>.</p>-->
      </fos:errors>
      <fos:notes>
         <p>It is <rfc2119>recommended</rfc2119> that a processor that implements schema awareness should return typed nodes.
            The concept of “schema awareness”, however, is a matter for host languages to define and is outside
            the scope of the function library specification.</p>
         <p>The declarations and definitions in the schema are not automatically available in
            the static context of the <function>fn:analyze-string</function> call (or of any other
            expression). The contents of the static context are host-language defined, and in some
            host languages are implementation-defined.</p>
         <p>The schema defines the outermost element, <code>analyze-string-result</code>, in such
         a way that mixed content is permitted. In fact the element will only have element nodes (<code>match</code>
         and <code>non-match</code>) as its children, never text nodes. Although this might have originally been an
            oversight, defining the <code>analyze-string-result</code> element with <code>mixed="true"</code> allows it
         to be atomized, which is potentially useful (the atomized value will be the original input string),
         and the capability has therefore been retained for compatibility with the 3.0 version of this
         specification.</p>
         <p>The rules for <termref def="dt-disjoint-matching-segments"/> allow a zero-length matching
            segment to immediately follow a non-zero-length matching segment (they are not considered to
            overlap). This means, for example, that the regular expression <code>.*</code>
         will typically produce two matches: one matching segment containing all the characters in the 
         input string, and a second zero-length matching seqment at the end position of the string.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>In the following examples, the result document is shown in serialized form, with
               whitespace between the element nodes. This whitespace is not actually present in the
               result.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>analyze-string("The cat sat on the mat.", "\w+")</fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true" as="element()"><eg><![CDATA[
<analyze-string-result xmlns="http://www.w3.org/2005/xpath-functions">
  <match>The</match>
  <non-match> </non-match>
  <match>cat</match>
  <non-match> </non-match>
  <match>sat</match>
  <non-match> </non-match>
  <match>on</match>
  <non-match> </non-match>
  <match>the</match>
  <non-match> </non-match>
  <match>mat</match>
  <non-match>.</non-match>
</analyze-string-result>]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>analyze-string("08-12-03", "^(\d+)\-(\d+)\-(\d+)$")</eg></fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true" as="element()"><![CDATA[
<analyze-string-result xmlns="http://www.w3.org/2005/xpath-functions">
  <match>
    <group nr="1">08</group>-<group nr="2">12</group>-<group nr="3">03</group>
  </match>
</analyze-string-result>]]></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>analyze-string("A1,C15,,D24, X50,", "([A-Z])([0-9]+)")</eg></fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true" as="element()"><![CDATA[
<analyze-string-result xmlns="http://www.w3.org/2005/xpath-functions">
  <match>
    <group nr="1">A</group>
    <group nr="2">1</group>
  </match>
  <non-match>,</non-match>
  <match>
    <group nr="1">C</group>
    <group nr="2">15</group>
  </match>
  <non-match>,,</non-match>
  <match>
    <group nr="1">D</group>
    <group nr="2">24</group>
  </match>
  <non-match>, </non-match>
  <match>
    <group nr="1">X</group>
    <group nr="2">50</group>
  </match>
  <non-match>,</non-match>
</analyze-string-result>]]></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>analyze-string("Chapter 5", "(Chapter|Appendix)(?=\s+([0-9]+))")</eg></fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true" as="element()"><![CDATA[
<analyze-string-result xmlns="http://www.w3.org/2005/xpath-functions">
  <match>
    <group nr="1">Chapter</group>
    <lookahead-group nr="2" value="5" position="9"/>
  </match>
  <non-match> 5</non-match>  
</analyze-string-result>]]></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>analyze-string("There we go", "\b(?=(\w+))")</eg></fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true" as="element()"><![CDATA[
<analyze-string-result xmlns="http://www.w3.org/2005/xpath-functions">
  <match><lookahead-group nr="1" value="There" position="1"/></match>
  <non-match>There </non-match>
  <match><lookahead-group nr="1" value="we" position="7"/></match>
  <non-match>we </non-match>
  <match><lookahead-group nr="1" value="go" position="10"/></match>
  <non-match>go</non-match>
</analyze-string-result>]]></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="998" PR="1856" date="2025-03-18">
            <p>The output of the function is extended to allow the represention of
               captured groups found within lookahead assertions.</p>
         </fos:change>
         <fos:change issue="1911" PR="1913" date="2025-04-08">
            <p>It is now permitted for the regular expression to match a zero-length string.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="contains-token" prefix="fn">
      <fos:signatures>
         <fos:proto name="contains-token" return-type="xs:boolean">
            <fos:arg name="value" type="xs:string*"/>
            <fos:arg name="token" type="xs:string"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Determines whether or not any of the supplied strings, when 
            tokenized at whitespace boundaries, contains the supplied token,
            under the rules of the supplied collation.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns <code>false</code>.</p>
         <p>Leading and trailing whitespace is trimmed from <code>$token</code>. 
            If the trimmed value of <code>$token</code>
            is a zero-length string, the function returns <code>false</code>.</p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>
         <p>The function returns <code>true</code> if and only if there is string in <code>$value</code> which, 
            after tokenizing at whitespace boundaries, contains a token
         that is equal to the trimmed value of <code>$token</code> under
         the rules of the selected collation.</p>
       
      </fos:rules>
      <fos:equivalent style="xpath-expression">
some $t in ($value ! tokenize(.))
satisfies compare($t, replace($token, '^\s*|\s*$', ''), $collation) eq 0
      </fos:equivalent>
      <fos:notes>
         <p>Interior whitespace within <code>$token</code> will cause the function to return <code>false</code>,
         unless such whitespace is ignored by the selected collation.</p>
         <p>This function can be used for processing space-separated attribute values
            (for example, the XHTML and DITA class attribute),
            where one often needs to test for the presence
            of a single token in a space-separated list. The function is designed to work
            both when the attribute has been validated against an XSD list type, and when it
            appears as a single untyped string. It differs from the
            HTML 5 definition in that HTML 5 recognizes form feed (x0C) as a separator.
            To reproduce the HTML token matching behavior, the HTML ASCII case-insensitive collation
            should be used: see <specref
               ref="html-ascii-case-insensitive-collation"/>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>contains-token("red green blue ", "red")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>contains-token(("red", "green", "blue"), " red ")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>contains-token("red, green, blue", "red")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>contains-token(
  "red green blue",
  "RED",
  "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="resolve-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="resolve-uri" return-type="xs:anyURI?">
            <fos:arg name="href" type="xs:string?"/>
            <fos:arg name="base" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Resolves a relative IRI reference against an absolute IRI.</p>
      </fos:summary>
      <fos:rules>


         <p>The function is defined to operate on IRI references as defined in <bibref ref="rfc3987"
               />, and the implementation <rfc2119>must</rfc2119> permit all arguments that are valid
            according to that specification. In addition, the implementation <rfc2119>may</rfc2119>
            accept some or all strings that conform to the rules for (absolute or relative) Legacy
            Extended IRI references as defined in <bibref
               ref="LEIRI"
            />. For the purposes of this
            section, the terms IRI and IRI reference include these extensions, insofar as the
            implementation chooses to support them.</p>

         <p>The following rules apply in order:</p>

         <olist>
            <item>
               <p>If <code>$href</code> is the empty sequence, the function returns the empty
               sequence.</p>
            </item>
            <item>
               <p>If <code>$href</code> is an absolute IRI (as defined above), then it is returned
               unchanged.</p>
            </item>
            <item>
               <p>If the <code>$base</code> argument is the empty sequence, then:</p>
               <olist>
                  <item>
                     <p>If the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> 
                        in the dynamic context is not absent, it is used as the effective
                        value of <code>$base</code>.</p>
                  </item>
                  <item>
                     <p>Otherwise, a dynamic error is raised: <phrase><errorref class="NS"
                              code="0005"/></phrase>.</p>
                  </item>
               </olist>
            </item>
            <item>
               <p>The function resolves the relative IRI reference <code>$href</code>
               against the base IRI <code>$base</code> using the algorithm defined in <bibref
                     ref="rfc3986"/>, adapted by treating any <termref def="character"
                     >character</termref>
               that would not be valid in an RFC3986 URI or relative reference in the same way that
               RFC3986 treats unreserved characters. No percent-encoding takes place.</p>
            </item>
         </olist>
      </fos:rules>
      <fos:errors>
         <p>The first form of this function resolves <code>$href</code> against the value of the
            base-uri property from the static context. A dynamic error is raised <errorref
               class="NS" code="0005"
            /> if the base-uri property is not initialized in the static
            context. </p>
         <p>A dynamic error is raised <errorref class="RG" code="0002"
            /> if <code>$href</code>
            is not a valid IRI according to the rules of RFC3987, extended with an
            implementation-defined subset of the extensions permitted in LEIRI, or if it is not a
            suitable relative reference to use as input to the RFC3986 resolution algorithm extended
            to handle additional unreserved characters. </p>
         <p>A dynamic error is raised <errorref class="RG" code="0002"
            /> if <code>$base</code> is
            not a valid IRI according to the rules of RFC3987, extended with an
            implementation-defined subset of the extensions permitted in LEIRI, or if it is not a
            suitable IRI to use as input to the chosen resolution algorithm (for example, if it is a
            relative IRI reference<phrase diff="add" at="2023-04-04"> or</phrase><phrase
            diff="del" at="2023-04-04">,</phrase> if it is a non-hierarchic URI<phrase
            diff="del" at="2023-04—04">, or if it contains a fragment
            identifier</phrase>).<phrase diff="add" at="2023-04-04"> In XPath 4.0, attempting
         to resolve against an absolute URI that includes a fragment identifier is no longer
         an error, the fragment identifier is simply ignored. A narrow reading of RFC 3986
         might seem to forbid this, but in practice the interpretation is non-controversial
         and the practice is widely supported.</phrase></p>
         <p>A dynamic error is raised <errorref class="RG" code="0009"
            /> if the chosen resolution
            algorithm fails for any other reason. </p>
      </fos:errors>
      <fos:notes>
         <p>Resolving a URI does not dereference it. This is merely a syntactic operation on two
               <termref
               def="string">strings</termref>.</p>
         <p>The algorithms in the cited RFCs include some variations that are optional or
            recommended rather than mandatory; they also describe some common practices that are not
            recommended, but which are permitted for backwards compatibility. Where the cited RFCs
            permit variations in behavior, so does this specification. </p>
         <p>Throughout this family of specifications, the phrase "resolving a relative URI (or IRI)
            reference" should be understood as using the rules of this function, unless otherwise
            stated.</p>
         <p>RFC3986 defines an algorithm for resolving relative references 
            in the context of the URI syntax defined in that RFC. RFC3987 describes a modification 
            to that algorithm to make it applicable to IRIs (specifically: additional characters 
            permitted in an IRI are handled the same way that RFC3986 handles unreserved characters). 
            The LEIRI specification does not explicitly define a resolution algorithm, but suggests 
            that it <emph>should not</emph> be done by converting the LEIRI to a URI, and 
            <emph>should not</emph> involve percent-encoding. This specification fills this gap 
            by defining resolution for LEIRIs in the same way that RFC3987 defines resolution for IRIs,
            that is by specifying that additional characters are handled as unreserved characters.</p>
      </fos:notes>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The optional second argument can now be supplied as the empty sequence.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="true" prefix="fn">
      <fos:signatures>
         <fos:proto name="true" return-type="xs:boolean"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:boolean</code> value <code>true</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The result is equivalent to <code>xs:boolean("1")</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>true()</fos:expression>
               <fos:result>xs:boolean(1)</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="false" prefix="fn">
      <fos:signatures>
         <fos:proto name="false" return-type="xs:boolean"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:boolean</code> value <code>false</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The result is equivalent to <code>xs:boolean("0")</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>false()</fos:expression>
               <fos:result>xs:boolean(0)</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <!--<fos:function name="boolean-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="boolean-equal" return-type="xs:boolean">
            <fos:arg name="value1" type="xs:boolean"/>
            <fos:arg name="value2" type="xs:boolean"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:boolean numeric"
            >Defines the semantics of the <code>eq</code>
         operator when applied to two <code>xs:boolean</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if the two arguments are the same boolean value.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>true</code> if both arguments are <code>true</code> or if
            both arguments are <code>false</code>. It returns <code>false</code> if one of the
            arguments is <code>true</code> and the other argument is <code>false</code>. </p>
      </fos:rules>
   </fos:function>-->
   <!--<fos:function name="boolean-less-than" prefix="op">
      <fos:signatures>
         <fos:proto name="boolean-less-than" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:boolean"/>
            <fos:arg name="arg2" type="xs:boolean"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="lt" types="xs:boolean numeric" other-operators="ge"
            >Defines the
         semantics of the <code>lt</code> operator when applied to two <code>xs:boolean</code> values. Also
         used in the definition of the <code>ge</code> operator.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if the first argument is <code>false</code> and the second is <code>true</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>true</code> if <code>$arg1</code> is <code>false</code> and
               <code>$arg2</code> is <code>true</code>. Otherwise, it returns
            <code>false</code>.</p>
      </fos:rules>
   </fos:function>-->

   <fos:function name="boolean" prefix="fn">
      <fos:signatures>
         <fos:proto name="boolean" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="inspection" example="42"/>
         </fos:proto>
      </fos:signatures>
      <fos:summary>
         <p>Computes the effective boolean value of the sequence <code>$input</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function computes the effective boolean value of a sequence, defined according to
            the following rules. See also <xspecref
               spec="XP40" ref="id-ebv"/>.</p>
         <ulist>
            <item>
               <p>If <code>$input</code> is the empty sequence, <function>fn:boolean</function> returns
                     <code>false</code>.</p>
            </item>
            <item>
               <p>If <code>$input</code> is a sequence whose first item is a <xtermref spec="DM40" ref="dt-GNode"/>
                  (a generalized node), <function>fn:boolean</function> returns <code>true</code>.</p>
            </item>
            <item>
               <p>If <code>$input</code> is a singleton value of type <code>xs:boolean</code> or of a type 
                  derived from <code>xs:boolean</code>, <function>fn:boolean</function> returns
                     <code>$input</code>.</p>
            </item>
            <item>
               <p>If <code>$input</code> is a singleton value of type <code>xs:untypedAtomic</code>, 
                  <code>xs:string</code>, <code>xs:anyURI</code>, or a type derived from <code>xs:string</code>
                  or <code>xs:anyURI</code>, <function>fn:boolean</function> returns <code>false</code> if the operand value has
                  zero length; otherwise it returns <code>true</code>.</p>
            </item>
            <item>
               <p>If <code>$input</code> is a singleton value of any numeric type or a type derived
                  from a numeric type, <function>fn:boolean</function> returns <code>false</code> if the
                  operand value is <code>NaN</code> or is numerically equal to zero; otherwise it
                  returns <code>true</code>.</p>
            </item>
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>In all cases other than those listed above, <function>fn:boolean</function> raises a type error <errorref
               class="RG" code="0006"/>.</p>
      </fos:errors>
      <fos:notes>
         <p>The result of this function is not necessarily the same as <code>$input cast as
               xs:boolean</code>. For example, <code>fn:boolean("false")</code> returns the value
               <code>true</code> whereas <code>"false" cast as xs:boolean</code> (which can also be
            written <code>xs:boolean("false")</code>) returns <code>false</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="abc" id="v-boolean-abc"
            select="(&quot;a&quot;, &quot;b&quot;, &quot;&quot;)"/>
         <fos:example>
            <fos:test use="v-boolean-abc">
               <fos:expression>boolean($abc[1])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-boolean-abc">
               <fos:expression>boolean($abc[0])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-boolean-abc">
               <fos:expression>boolean($abc[3])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-boolean-abc">
               <fos:expression>fn:boolean($abc)</fos:expression>
               <fos:error-result error-code="FORG0006"/>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-boolean-abc">
               <fos:expression>fn:boolean([])</fos:expression>
               <fos:error-result error-code="FORG0006"/>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="not" prefix="fn">
      <fos:signatures>
         <fos:proto name="not" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="inspection" example="42"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the effective boolean value of <code>$input</code> is
               <code>false</code>, or <code>false</code> if it is <code>true</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The value of <code>$input</code> is first reduced to an effective boolean value by
            applying the <code>fn:boolean()</code> function. The function returns <code>true</code>
            if the effective boolean value is <code>false</code>, or <code>false</code> if the
            effective boolean value is <code>true</code>. </p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>not(true())</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>not(())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>not("false")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>fn:not(1 to 10)</fos:expression>
               <fos:error-result error-code="FORG0006"/>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <!--<fos:function name="yearMonthDuration-less-than" prefix="op">
      <fos:signatures>
         <fos:proto name="yearMonthDuration-less-than" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:yearMonthDuration"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="lt" types="xs:yearMonthDuration numeric" other-operators="ge"
            >Defines
         the semantics of the <code>lt</code> operator when applied to two <code>xs:yearMonthDuration</code>
         values. Also used in the definition of the <code>ge</code> operator.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if <code>$arg1</code> is a shorter duration than <code>$arg2</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If the number of months in <code>$arg1</code> is numerically less than the
            number of months in <code>$arg2</code>, the function returns <code>true</code>.</p>
         <p>Otherwise, the function returns <code>false</code>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either or both durations may be negative.</p>
      </fos:notes>
   </fos:function>-->

   <!--<fos:function name="dayTimeDuration-less-than" prefix="op">
      <fos:signatures>
         <fos:proto name="dayTimeDuration-less-than" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:dayTimeDuration"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="lt" types="xs:dayTimeDuration numeric" other-operators="ge"
            >Defines the
         semantics of the <code>lt</code> operator when applied to two <code>xs:dayTimeDuration</code> values.
         Also used in the definition of the <code>ge</code> operator.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if <code>$arg1</code> is a shorter duration than <code>$arg2</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If the number of seconds in <code>$arg1</code> is numerically less than the
            number of seconds in <code>$arg2</code>, the function returns <code>true</code>.</p>
         <p>Otherwise, the function returns <code>false</code>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either or both durations may be negative</p>
      </fos:notes>
   </fos:function>
-->
   <!--<fos:function name="duration-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="duration-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:duration"/>
            <fos:arg name="arg2" type="xs:duration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:duration numeric" other-operators="ne"
            >Defines the
         semantics of the <code>eq</code> operators when applied to two <code>xs:duration</code> values. Also
         used in the definition of the <code>ne</code> operator.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if <code>$arg1</code> and <code>$arg2</code> are durations of the same
            length.</p>
      </fos:summary>
      <fos:rules>
         <p>If the <code>xs:yearMonthDuration</code> components of <code>$arg1</code> and
               <code>$arg2</code> are equal and the <code>xs:dayTimeDuration</code> components of
               <code>$arg1</code> and <code>$arg2</code> are equal, the function returns
               <code>true</code>.</p>
         <p>Otherwise, the function returns <code>false</code>.</p>
         <p>The semantics of this function are:</p>
         <eg xml:space="preserve">
xs:yearMonthDuration($arg1) div xs:yearMonthDuration('P1M')  eq
xs:yearMonthDuration($arg2) div xs:yearMonthDuration('P1M')
    and
xs:dayTimeDuration($arg1) div xs:dayTimeDuration('PT1S')  eq
xs:dayTimeDuration($arg2) div xs:dayTimeDuration('PT1S')
</eg>
         <p>that is, the function returns <code>true</code> if the months and seconds values of the
            two durations are equal.</p>
      </fos:rules>
      <fos:notes>
         <p>Note that this function, like any other, may be applied to arguments that are derived
            from the types given in the function signature, including the two subtypes
               <code>xs:dayTimeDuration</code> and <code>xs:yearMonthDuration</code>. With the
            exception of the zero-length duration, no instance of <code>xs:dayTimeDuration</code>
            can ever be equal to an instance of <code>xs:yearMonthDuration</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:duration("P1Y"),
  xs:duration("P12M")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:duration("PT24H"),
  xs:duration("P1D")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:duration("P1Y"),
  xs:duration("P365D")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:yearMonthDuration("P0Y"),
  xs:dayTimeDuration("P0D")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:yearMonthDuration("P1Y"),
  xs:dayTimeDuration("P365D")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:yearMonthDuration("P2Y"),
  xs:yearMonthDuration("P24M")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:dayTimeDuration("P10D"),
  xs:dayTimeDuration("PT240H")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:duration("P2Y0M0DT0H0M0S"),
  xs:yearMonthDuration("P24M")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:duration-equal(
  xs:duration("P0Y0M10D"),
  xs:dayTimeDuration("PT240H")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>-->
   
   <fos:function name="seconds" prefix="fn">
      <fos:signatures>
         <fos:proto name="seconds" return-type="xs:dayTimeDuration?">
            <fos:arg name="value" type="xs:decimal?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an <code>xs:dayTimeDuration</code> whose length is a given number of seconds.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:dayTimeDuration</code> value whose length
            in seconds is equal to <code>$value</code>. </p>
            <p>If <code>$value</code> is negative then the result will be a negative duration.</p>
         <p>For handling of overflow and underflow, see <specref ref="duration-limits"/>.</p>

      </fos:rules>
      <fos:notes>
         <p>The result of <code>seconds($n)</code> is approximately equal to the result of
         the expression <code>xs:dayTimeDuration('PT1S') * $n</code>. The equivalence is only
         approximate, because <code>seconds($n)</code> uses the exact <code>xs:decimal</code>
         value supplied, whereas multiplying a duration by a number first converts the number
         to an <code>xs:double</code> value, which may lose precision.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds(1)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('PT1S')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds(0.001)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('PT0.001S')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds(60)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('PT1M')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds(86400)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('P1D')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds(-5400)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('-PT1H30M')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>xs:dateTime('1970-01-01T00:00:00Z') + 1706702400 * seconds(1)</eg></fos:expression>
               <fos:result>xs:dateTime('2024-01-31T12:00:00Z')</fos:result>
               <fos:postamble>The expression converts a Unix timestamp to an <code>xs:dateTime</code> value</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>(
  xs:dateTime('2024-01-31T12:00:00Z') -
  xs:dateTime('1970-01-01T00:00:00Z')
) div seconds(1)</eg></fos:expression>
               <fos:result>1706702400</fos:result>
               <fos:postamble>The expression converts an <code>xs:dateTime</code> value to a Unix timestamp</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="959" PR="984" date="2024-02-06"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="years-from-duration" prefix="fn">
      <fos:signatures>
         <fos:proto name="years-from-duration" return-type="xs:integer?">
            <fos:arg name="value" type="xs:duration?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of years in a duration.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> representing the years
            component in <code>$value</code>. Given that a duration
            is a <code>($months, $seconds)</code> tuple, the result is the value of <code>($months idiv 12)</code>.</p>
         <p>If <code>$value</code> is a negative duration then the result will be negative.</p>
         <p>If <code>$value</code> is an <code>xs:dayTimeDuration</code> the function
            returns <code>0</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>years-from-duration(
  xs:yearMonthDuration("P20Y15M")
)</eg></fos:expression>
               <fos:result>21</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>years-from-duration(
  xs:yearMonthDuration("-P15M")
)</eg></fos:expression>
               <fos:result>-1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>years-from-duration(
  xs:dayTimeDuration("-P2DT15H")
)</eg></fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>years-from-duration(
  xs:duration("P1Y1000D")
)</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>To capture whole portions of years reflected in the
                     <code>xs:dayTimeDuration</code> component, it must first be converted to an
                     <code>xs:yearMonthDuration</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="months-from-duration" prefix="fn">
      <fos:signatures>
         <fos:proto name="months-from-duration" return-type="xs:integer?">
            <fos:arg name="value" type="xs:duration?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of months in a duration.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> representing the months
            component in <code>$value</code>. Given that a duration
               is a <code>($months, $seconds)</code> tuple, the result is the value of <code>($months mod 12)</code>.</p>
         <p>If <code>$value</code> is a negative duration then the result will be negative.</p>
         <p>If <code>$value</code> is an <code>xs:dayTimeDuration</code> the function
            returns <code>0</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>months-from-duration(
  xs:yearMonthDuration("P20Y15M")
)</eg></fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>months-from-duration(
  xs:yearMonthDuration("-P20Y18M")
)</eg></fos:expression>
               <fos:result>-6</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>months-from-duration(
  xs:dayTimeDuration("-P2DT15H0M0S")
)</eg></fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>months-from-duration(
   xs:duration("P1M100D")
)</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>To capture whole portions of months reflected in the
                     <code>xs:dayTimeDuration</code> component, it must first be converted to an
                     <code>xs:yearMonthDuration</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="days-from-duration" prefix="fn">
      <fos:signatures>
         <fos:proto name="days-from-duration" return-type="xs:integer?">
            <fos:arg name="value" type="xs:duration?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of days in a duration.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> representing the days
            component in <code>$value</code>. Given that a duration
               is a <code>($months, $seconds)</code> tuple, the result is <code>($seconds idiv 86400)</code>.</p>
         <p>If <code>$value</code> is a negative duration then the result will be negative.</p>
         <p>If <code>$value</code> is an <code>xs:yearMonthDuration</code> the function returns <code>0</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>days-from-duration(
  xs:dayTimeDuration("P3DT10H")
)</eg></fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>days-from-duration(
  xs:dayTimeDuration("P3DT55H")
)</eg></fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>days-from-duration(
  xs:yearMonthDuration("P3Y5M")
)</eg></fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>days-from-duration(
   xs:duration("P1Y1D")
)</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>To capture days reflected in the <code>xs:yearMonthDuration</code>
                  component, it must first be converted to an
                  <code>xs:dayTimeDuration</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="hours-from-duration" prefix="fn">
      <fos:signatures>
         <fos:proto name="hours-from-duration" return-type="xs:integer?">
            <fos:arg name="value" type="xs:duration?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of hours in a duration.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> representing the hours
            component in <code>$value</code>. <phrase>Given that a duration
               is a <code>($months, $seconds)</code> tuple, the result is the value of <code>($seconds mod 86400) idiv 3600</code></phrase>.</p>
         <p>If <code>$value</code> is a negative duration then the result will be negative.</p>
         <p>If <code>$value</code> is an <code>xs:yearMonthDuration</code> the function returns <code>0</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-duration(
  xs:dayTimeDuration("P3DT10H")
)</eg></fos:expression>
               <fos:result>10</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-duration(
  xs:dayTimeDuration("P3DT12H32M12S")
)</eg></fos:expression>
               <fos:result>12</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-duration(
  xs:dayTimeDuration("PT123H")
)</eg></fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-duration(
  xs:dayTimeDuration("-P3DT10H")
)</eg></fos:expression>
               <fos:result>-10</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-duration(
   xs:duration("P1YT1H")
)</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>To capture hours reflected in the <code>xs:yearMonthDuration</code>
                  component, it must first be converted to an
                  <code>xs:dayTimeDuration</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="minutes-from-duration" prefix="fn">
      <fos:signatures>
         <fos:proto name="minutes-from-duration" return-type="xs:integer?">
            <fos:arg name="value" type="xs:duration?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of minutes in a duration.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> representing the minutes
            component in  <code>$value</code>. Given that a duration
               is a <code>($months, $seconds)</code> tuple, the result is the value of <code>($seconds mod 3600) idiv 60</code>.</p>
         <p>If <code>$value</code> is a negative duration then the result will be negative.</p>
         <p>If <code>$value</code> is an <code>xs:yearMonthDuration</code> the function returns <code>0</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>minutes-from-duration(
  xs:dayTimeDuration("P3DT10H")
)</eg></fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>minutes-from-duration(
  xs:dayTimeDuration("-P5DT12H30M")
)</eg></fos:expression>
               <fos:result>-30</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>minutes-from-duration(
   xs:duration("P1YT1M")
)</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>To capture minutes reflected in the <code>xs:yearMonthDuration</code>
                  component, it must first be converted to an
                  <code>xs:dayTimeDuration</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="seconds-from-duration" prefix="fn">
      <fos:signatures>
         <fos:proto name="seconds-from-duration" return-type="xs:decimal?">
            <fos:arg name="value" type="xs:duration?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of seconds in a duration.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:decimal</code> representing the seconds
            component in <code>$value</code>. Given that a duration
               is a <code>($months, $seconds)</code> tuple, the result is the value of <code>($seconds mod 60)</code>
            as an <code>xs:decimal</code>.</p>
         <p>If <code>$value</code> is a negative duration then the result will be negative.</p>
         <p>If <code>$value</code> is an <code>xs:yearMonthDuration</code> the function returns <code>0</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds-from-duration(
  xs:dayTimeDuration("P3DT10H12.5S")
)</eg></fos:expression>
               <fos:result>12.5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds-from-duration(
  xs:dayTimeDuration("-PT256S")
)</eg></fos:expression>
               <fos:result>-16.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds-from-duration(
   xs:duration("P1YT1S")
)</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>To capture seconds reflected in the <code>xs:yearMonthDuration</code>
                  component of an <code>xs:duration</code>, it must first be converted to an
                  <code>xs:dayTimeDuration</code>.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds-from-duration(
   xs:duration("P1YT1S")
)</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>To capture seconds reflected in the <code>xs:yearMonthDuration</code>
                  component, it must first be converted to an
                  <code>xs:dayTimeDuration</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="add-yearMonthDurations" prefix="op">
      <fos:signatures>
         <fos:proto name="add-yearMonthDurations" return-type="xs:yearMonthDuration">
            <fos:arg name="arg1" type="xs:yearMonthDuration"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="xs:yearMonthDuration numeric"
            >Defines the semantics of the
         <code>+</code> operator when applied to two <code>xs:yearMonthDuration</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns the result of adding two <code>xs:yearMonthDuration</code> values. </p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of adding <code>$arg1</code> to <code>$arg2</code>. 
            The result will be an <code>xs:yearMonthDuration</code> whose
            length in months is equal to the length in months of <code>$arg1</code> plus the length
            in months of <code>$arg2</code>.</p>
         <p>For handling of overflow, see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either duration (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-yearMonthDurations(
  xs:yearMonthDuration("P2Y11M"),
  xs:yearMonthDuration("P3Y3M")
)</eg></fos:expression>
               <fos:result>xs:yearMonthDuration("P6Y2M")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-yearMonthDurations" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-yearMonthDurations" return-type="xs:yearMonthDuration">
            <fos:arg name="arg1" type="xs:yearMonthDuration"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:yearMonthDuration numeric"
            >Defines the semantics of the
         <code>-</code> operator when applied to two <code>xs:yearMonthDuration</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns the result of subtracting one <code>xs:yearMonthDuration</code> value from
            another. </p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of subtracting <code>$arg2</code> from 
            <code>$arg1</code>. The result will be an <code>xs:yearMonthDuration</code>
            whose length in months is equal to the length in months of <code>$arg1</code> minus the
            length in months of <code>$arg2</code>.</p>
         <p>For handling of overflow, see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either duration (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-yearMonthDurations(
  xs:yearMonthDuration("P2Y11M"),
  xs:yearMonthDuration("P3Y3M")
)</eg></fos:expression>
               <fos:result>xs:yearMonthDuration("-P4M")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="multiply-yearMonthDuration" prefix="op">
      <fos:signatures>
         <fos:proto name="multiply-yearMonthDuration" return-type="xs:yearMonthDuration">
            <fos:arg name="arg1" type="xs:yearMonthDuration"/>
            <fos:arg name="arg2" type="xs:double"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="*" types="xs:yearMonthDuration numeric"
            >Defines the semantics of the
         <code>*</code> operator when applied to an <code>xs:yearMonthDuration</code> and a numeric
         value.</fos:opermap>
      <fos:summary>
         <p>Returns the result of multiplying  <code>$arg1</code> by <code>$arg2</code>.
            The result is rounded to the nearest month.</p>
      </fos:summary>
      <fos:rules>
         <p>The result is the <code>xs:yearMonthDuration</code> whose length in months is equal to
            the result of applying the <function>fn:round</function> function to the value obtained by
            multiplying the length in months of <code>$arg1</code> by the value of
               <code>$arg2</code>.</p>
         <p>If <code>$arg2</code> is positive or negative zero, the result is a zero-length
            duration. If <code>$arg2</code> is positive or negative infinity, the result overflows
            and is handled as described in <specref
               ref="duration-limits"/>. </p>
         <p>For handling of overflow, underflow, and rounding, see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="CA" code="0005"
               /> if <code>$arg2</code> is
               <code>NaN</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>Either duration (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:multiply-yearMonthDuration(
  xs:yearMonthDuration("P2Y11M"),
  2.3
)</eg></fos:expression>
               <fos:result>xs:yearMonthDuration("P6Y9M")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="divide-yearMonthDuration" prefix="op">
      <fos:signatures>
         <fos:proto name="divide-yearMonthDuration" return-type="xs:yearMonthDuration">
            <fos:arg name="arg1" type="xs:yearMonthDuration"/>
            <fos:arg name="arg2" type="xs:double"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="div" types="xs:yearMonthDuration numeric"
            >Defines the semantics of the
         <code>div</code> operator when applied to an <code>xs:yearMonthDuration</code> and a numeric
         value.</fos:opermap>
      <fos:summary>
         <p>Returns the result of dividing <code>$arg1</code> by <code>$arg2</code>.
            The result is rounded to the nearest month.</p>
      </fos:summary>
      <fos:rules>
         <p>The result is the <code>xs:yearMonthDuration</code> whose length in months is equal to
            the result of applying the <function>fn:round</function> function to the value obtained by
            dividing the length in months of <code>$arg1</code> by the value of
            <code>$arg2</code>.</p>
         <p>If <code>$arg2</code> is positive or negative infinity, the result is a zero-length
            duration. If <code>$arg2</code> is positive or negative zero, the result overflows and
            is handled as described in <specref
               ref="duration-limits"/>. </p>
         <p>For handling of overflow, underflow, and rounding, 
            see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="CA" code="0005"
               /> if <code>$arg2</code> is
               <code>NaN</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>Either operand (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:divide-yearMonthDuration(
  xs:yearMonthDuration("P2Y11M"),
  1.5
)</eg></fos:expression>
               <fos:result>xs:yearMonthDuration("P1Y11M")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="divide-yearMonthDuration-by-yearMonthDuration" prefix="op">
      <fos:signatures>
         <fos:proto name="divide-yearMonthDuration-by-yearMonthDuration" return-type="xs:decimal">
            <fos:arg name="arg1" type="xs:yearMonthDuration"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="div" types="xs:yearMonthDuration numeric"
            >Defines the semantics of the
         <code>div</code> operator when applied to two <code>xs:yearMonthDuration</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns the ratio of two <code>xs:yearMonthDuration</code> values.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of dividing the length in months of <code>$arg1</code>
            by the length in months of <code>$arg2</code>, according to the rules of the
               <code>op:numeric-divide</code> function for integer operands.</p>
         <p>For handling of overflow, underflow, and rounding, 
            see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either duration (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:divide-yearMonthDuration-by-yearMonthDuration(
  xs:yearMonthDuration("P3Y4M"),
  xs:yearMonthDuration("-P1Y4M")
)</eg></fos:expression>
               <fos:result>-2.5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>The following example demonstrates how to calculate the length of an
                  <code>xs:yearMonthDuration</code> value in months:</p>
            <fos:test>
               <fos:expression><eg>op:divide-yearMonthDuration-by-yearMonthDuration(
  xs:yearMonthDuration("P3Y4M"),
  xs:yearMonthDuration("P1M")
)</eg></fos:expression>
               <fos:result>40</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="add-dayTimeDurations" prefix="op">
      <fos:signatures>
         <fos:proto name="add-dayTimeDurations" return-type="xs:dayTimeDuration">
            <fos:arg name="arg1" type="xs:dayTimeDuration"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="xs:dayTimeDuration numeric"
            >Defines the semantics of the <code>+</code>
         operator when applied to two <code>xs:dayTimeDuration</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns the sum of two <code>xs:dayTimeDuration</code> values.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of adding <code>$arg1</code> to 
            <code>$arg2</code>. The result is the <code>xs:dayTimeDuration</code> whose length in
            seconds is equal to the sum of the length in seconds of the two input durations.</p>
         <p>For handling of overflow, see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either duration (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-dayTimeDurations(
  xs:dayTimeDuration("P2DT12H5M"),
  xs:dayTimeDuration("P5DT12H")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('P8DT5M')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-dayTimeDurations" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-dayTimeDurations" return-type="xs:dayTimeDuration">
            <fos:arg name="arg1" type="xs:dayTimeDuration"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:dayTimeDuration numeric"
            >Defines the semantics of the <code>-</code>
         operator when applied to two <code>xs:dayTimeDuration</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns the result of subtracting one <code>xs:dayTimeDuration</code> from another.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of subtracting <code>$arg2</code> from 
            <code>$arg1</code>. The result is the <code>xs:dayTimeDuration</code> whose
            length in seconds is equal to the length in seconds of <code>$arg1</code> minus the
            length in seconds of <code>$arg2</code>.</p>
         <p>For handling of overflow, see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either duration (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-dayTimeDurations(
  xs:dayTimeDuration("P2DT12H"),
  xs:dayTimeDuration("P1DT10H30M")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('P1DT1H30M')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="multiply-dayTimeDuration" prefix="op">
      <fos:signatures>
         <fos:proto name="multiply-dayTimeDuration" return-type="xs:dayTimeDuration">
            <fos:arg name="arg1" type="xs:dayTimeDuration"/>
            <fos:arg name="arg2" type="xs:double"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="*" types="xs:dayTimeDuration numeric"
            >Defines the semantics of the <code>*</code>
         operator when applied to an <code>xs:dayTimeDuration</code> and a numeric
         value.</fos:opermap>
      <fos:summary>
         <p>Returns the result of multiplying a <code>xs:dayTimeDuration</code> by a number.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of multiplying <code>$arg1</code> by
               <code>$arg2</code>. The result is the <code>xs:dayTimeDuration</code> whose length in
            seconds is equal to the length in seconds of <code>$arg1</code> multiplied by the
            numeric value <code>$arg2</code>.</p>

         <p>If <code>$arg2</code> is positive or negative zero, the result is a zero-length
            duration. If <code>$arg2</code> is positive or negative infinity, the result overflows
            and is handled as described in <specref
               ref="duration-conformance"/>. </p>
         <p>For handling of overflow, underflow, and rounding, see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="CA" code="0005"
               /> if <code>$arg2</code> is
               <code>NaN</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>Either operand (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:multiply-dayTimeDuration(
  xs:dayTimeDuration("PT2H10M"),
  2.1
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('PT4H33M')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="divide-dayTimeDuration" prefix="op">
      <fos:signatures>
         <fos:proto name="divide-dayTimeDuration" return-type="xs:dayTimeDuration">
            <fos:arg name="arg1" type="xs:dayTimeDuration"/>
            <fos:arg name="arg2" type="xs:double"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="div" types="xs:dayTimeDuration numeric"
            >Defines the semantics of the
         <code>div</code> operator when applied to two <code>xs:dayTimeDuration</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns the result of multiplying a <code>xs:dayTimeDuration</code> by a number.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of dividing <code>$arg1</code> by
               <code>$arg2</code>. The result is the <code>xs:dayTimeDuration</code> whose length in
            seconds is equal to the length in seconds of <code>$arg1</code> divided by the numeric
            value <code>$arg2</code>.</p>
         <p>If <code>$arg2</code> is positive or negative infinity, the result is a zero-length
            duration. If <code>$arg2</code> is positive or negative zero, the result overflows and
            is handled as described in <specref
               ref="duration-conformance"/>. </p>
 
         <p>For handling of overflow, underflow, and rounding, see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="CA" code="0005"
               /> if <code>$arg2</code> is
               <code>NaN</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>Either operand (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:divide-dayTimeDuration(
  xs:dayTimeDuration("P1DT2H30M10.5S"),
  1.5
)</eg></fos:expression>
               <fos:result>xs:duration("PT17H40M7S")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="divide-dayTimeDuration-by-dayTimeDuration" prefix="op">
      <fos:signatures>
         <fos:proto name="divide-dayTimeDuration-by-dayTimeDuration" return-type="xs:decimal">
            <fos:arg name="arg1" type="xs:dayTimeDuration"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="div" types="xs:dayTimeDuration numeric"
            >Defines the semantics of the
         <code>div</code> operator when applied to two <code>xs:dayTimeDuration</code> values.</fos:opermap>
      <fos:summary>
         <p>Returns the ratio of two <code>xs:dayTimeDuration</code> values, as a decimal
            number.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of dividing <code>$arg1</code> by
               <code>$arg2</code>. The result is the <code>xs:dayTimeDuration</code> whose length in
            seconds is equal to the length in seconds of <code>$arg1</code> divided by the length in
            seconds of <code>$arg2</code>. The calculation is performed by applying
               <code>op:numeric-divide</code> to the two <code>xs:decimal</code> operands.</p>
         <p>For handling of overflow, underflow, and rounding, 
            see <specref ref="duration-conformance"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>Either operand (and therefore the result) may be negative.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>round-half-to-even(
  op:divide-dayTimeDuration-by-dayTimeDuration(
    xs:dayTimeDuration("P2DT53M11S"), xs:dayTimeDuration("P1DT10H")
  ),
  4
)</eg></fos:expression>
               <fos:result>1.4378</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>This examples shows how to determine the number of seconds in a duration.</p>
            <fos:test>
               <fos:expression><eg>op:divide-dayTimeDuration-by-dayTimeDuration(
  xs:dayTimeDuration("P2DT53M11S"),
  seconds(1)
)</eg></fos:expression>
               <fos:result>175991.0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="dateTime" return-type="xs:dateTime?">
            <fos:arg name="date" type="xs:date?"/>
            <fos:arg name="time" type="xs:time?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an <code>xs:dateTime</code> value created by combining an <code>xs:date</code>
            and an <code>xs:time</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If either <code>$date</code> or <code>$time</code> is the empty sequence, the function
            returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:dateTime</code> whose date component is
            equal to <code>$date</code> and whose time component is equal to <code>$time</code>.</p>
         <p>The timezone of the result is computed as follows:</p>
         <ulist>
            <item>
               <p>If neither argument has a timezone, the result has no timezone.</p>
            </item>
            <item>
               <p>If exactly one of the arguments has a timezone, or if both arguments have the same
                  timezone, the result has this timezone.</p>
            </item>
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RG" code="0008"
            /> if the two arguments both
            have timezones and the timezones are different. </p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>dateTime(
  xs:date("1999-12-31"),
  xs:time("12:00:00")
)</eg></fos:expression>
               <fos:result>xs:dateTime("1999-12-31T12:00:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>dateTime(
  xs:date("1999-12-31"),
  xs:time("24:00:00")
)</eg></fos:expression>
               <fos:result>xs:dateTime("1999-12-31T00:00:00")</fos:result>
               <fos:postamble>This is because <code>"24:00:00"</code> is an alternate lexical form
                  for <code>"00:00:00"</code></fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="unix-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="unix-dateTime" return-type="xs:dateTimeStamp">
            <fos:arg name="value" type="xs:nonNegativeInteger?" default="0" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a dateTime value for a Unix time.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a dateTime value in UTC timezone for the Unix time specified
            by <code>$value</code> in milliseconds.
            The Unix time is defined in <bibref ref="ieee1003.1-2024"/>.</p>
         <p>If the implementation supports data types from XSD 1.1 then the returned value will be
            an instance of <code>xs:dateTimeStamp</code>. Otherwise, the only guarantees are that it
            will be an instance of <code>xs:dateTime</code> and will have a timezone component.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
xs:dateTime('1970-01-01T00:00:00Z') + ($value otherwise 0) * seconds(0.001)
      </fos:equivalent>
      <fos:notes>
         <p>By calling this convenience function, it can be ensured that the correct timezone
            is used for computing the Unix time.</p>
         <p>Note that Unix time does not account for leap seconds. It assumes that every day has
            86,400 seconds.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>unix-dateTime()</eg></fos:expression>
               <fos:result>xs:dateTime('1970-01-01T00:00:00Z')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>unix-dateTime(1)</eg></fos:expression>
               <fos:result>xs:dateTime('1970-01-01T00:00:00.001Z')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>unix-dateTime(86400000)</eg></fos:expression>
               <fos:result>xs:dateTime('1970-01-02T00:00:00Z')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Calculate the Unix time associated with a <code>xs:dateTime</code> value:</p>
            <eg>let $value := current-dateTime()
return ($value - unix-dateTime()) div seconds(0.001)</eg>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="959" PR="1358" date="2024-08-01"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <!--<fos:function name="dateTime-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="dateTime-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:dateTime"/>
            <fos:arg name="arg2" type="xs:dateTime"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:dateTime numeric" other-operators="ne le ge"
            >Defines the
         semantics of the <code>eq</code> operator when applied to two <code>xs:dateTime</code> values. Also
         used in the definition of the <code>ne</code>, <code>le</code> and <code>ge</code> operators.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the two supplied <code>xs:dateTime</code> values refer to the same
            instant in time.</p>
      </fos:summary>
      <fos:rules>
         <p>If either <code>$arg1</code> or <code>$arg2</code> has no timezone component, the
            effective value of the argument is obtained by substituting the implicit timezone from
            the dynamic evaluation context.</p>
         <p>The function then returns <code>true</code> if and only if the effective value of
               <code>$arg1</code> is equal to the effective value of <code>$arg2</code> according to
            the algorithm defined in section 3.2.7.4 of <bibref
               ref="xmlschema-2"/>
            <quote>Order relation on dateTime</quote> for <code>xs:dateTime</code> values with
            timezones. Otherwise the function returns <code>false</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code></p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:dateTime-equal(
  xs:dateTime("2002-04-02T12:00:00-01:00"),
  xs:dateTime("2002-04-02T17:00:00+04:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:dateTime-equal(
  xs:dateTime("2002-04-02T12:00:00"),
  xs:dateTime("2002-04-02T23:00:00+06:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:dateTime-equal(
  xs:dateTime("2002-04-02T12:00:00"),
  xs:dateTime("2002-04-02T17:00:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:dateTime-equal(
  xs:dateTime("2002-04-02T12:00:00"),
  xs:dateTime("2002-04-02T12:00:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:dateTime-equal(
  xs:dateTime("2002-04-02T23:00:00-04:00"),
  xs:dateTime("2002-04-03T02:00:00-01:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:dateTime-equal(
  xs:dateTime("1999-12-31T24:00:00"),
  xs:dateTime("2000-01-01T00:00:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:dateTime-equal(
  xs:dateTime("2005-04-04T24:00:00"),
  xs:dateTime("2005-04-04T00:00:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="dateTime-less-than" prefix="op">
      <fos:signatures>
         <fos:proto name="dateTime-less-than" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:dateTime"/>
            <fos:arg name="arg2" type="xs:dateTime"/>
         </fos:proto>
      </fos:signatures>

      <fos:opermap operator="lt" types="xs:dateTime numeric" other-operators="ge"
            >Defines the
         semantics of the <code>lt</code> operator when applied to two <code>xs:dateTime</code> values. Also
         used in the definition of the <code>ge</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the first argument represents an earlier instant in time
            than the second argument.</p>
      </fos:summary>
      <fos:rules>
         <p>If either <code>$arg1</code> or <code>$arg2</code> has no timezone component, the
            effective value of the argument is obtained by substituting the implicit timezone from
            the dynamic evaluation context.</p>
         <p>The function then returns <code>true</code> if and only if the effective value of
               <code>$arg1</code> is less than the effective value of <code>$arg2</code> according
            to the algorithm defined in section 3.2.7.4 of <bibref
               ref="xmlschema-2"/>
            <quote>Order relation on dateTime</quote> for <code>xs:dateTime</code> values with
            timezones. Otherwise the function returns <code>false</code>.</p>
      </fos:rules>
   </fos:function>
-->
   <!--<fos:function name="date-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="date-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:date"/>
            <fos:arg name="arg2" type="xs:date"/>
         </fos:proto>
      </fos:signatures>

      <fos:opermap operator="eq" types="xs:date numeric" other-operators="ne le ge"
            >Defines the
         semantics of the <code>eq</code> operator when applied to two <code>xs:date</code> values. Also used
         in the definition of the <code>ne</code>, <code>le</code> and <code>ge</code> operators.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if and only if the starting instants of the two supplied
               <code>xs:date</code> values are the same.</p>
      </fos:summary>
      <fos:rules>
         <p>The starting instant of an <code>xs:date</code> is the <code>xs:dateTime</code> at time
               <code>00:00:00</code> on that date.</p>
         <p>The function returns the result of the expression:</p>
         <eg xml:space="preserve">op:dateTime-equal(xs:dateTime($arg1), xs:dateTime($arg2))</eg>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:date-equal(
  xs:date("2004-12-25Z"),
  xs:date("2004-12-25+07:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>The starting instants are
                     <code>xs:dateTime("2004-12-25T00:00:00Z")</code> and
                     <code>xs:dateTime("2004-12-25T00:00:00+07:00")</code>. These are normalized to
                     <code>xs:dateTime("2004-12-25T00:00:00Z")</code> and
                     <code>xs:dateTime("2004-12-24T17:00:00Z")</code>. </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:date-equal(
  xs:date("2004-12-25-12:00"),
  xs:date("2004-12-26+12:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>-->
   <!--<fos:function name="date-less-than" prefix="op">
      <fos:signatures>
         <fos:proto name="date-less-than" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:date"/>
            <fos:arg name="arg2" type="xs:date"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="lt" types="xs:date numeric" other-operators="ge"
            >Defines the semantics
         of the <code>lt</code> operator when applied to two <code>xs:date</code> values. Also used in the
         definition of the <code>ge</code> operator.</fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if and only if the starting instant of <code>$arg1</code> is
            less than the starting instant of <code>$arg2</code>. Returns <code>false</code>
            otherwise.</p>
      </fos:summary>
      <fos:rules>
         <p>The starting instant of an <code>xs:date</code> is the <code>xs:dateTime</code> at time
               <code>00:00:00</code> on that date.</p>
         <p>The function returns the result of the expression:</p>
         <eg xml:space="preserve">op:dateTime-less-than(xs:dateTime($arg1), xs:dateTime($arg2))</eg>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:date-less-than(
  xs:date("2004-12-25Z"),
  xs:date("2004-12-25-05:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:date-less-than(
  xs:date("2004-12-25-12:00"),
  xs:date("2004-12-26+12:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>-->

   <!--<fos:function name="time-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="time-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:time"/>
            <fos:arg name="arg2" type="xs:time"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:time numeric" other-operators="ne le ge"
            >Defines the
         semantics of the <code>eq</code> operator when applied to two <code>xs:time</code> values. Also used
         in the definition of the <code>ne</code>, <code>le</code> and <code>ge</code> operators.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the two <code>xs:time</code> values represent the same
            instant in time, when treated as being times on the same date, before adjusting the
            timezone.</p>
      </fos:summary>
      <fos:rules>
         <p>Each of the supplied <code>xs:time</code> values is expanded to an
               <code>xs:dateTime</code> value by associating the time with an arbitrary date. The
            function returns the result of comparing these two <code>xs:dateTime</code> values using
               <code>op:dateTime-equal</code>.</p>
         <p>The result of the function is thus the same as the value of the expression:</p>
         <eg xml:space="preserve">op:dateTime-equal(
        dateTime(xs:date('1972-12-31'), $arg1), 
        dateTime(xs:date('1972-12-31'), $arg2))</eg>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the date components from the reference <code>xs:dateTime</code>
               correspond to <code>1972-12-31</code>.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:time-equal(
  xs:time("08:00:00+09:00"),
  xs:time("17:00:00-06:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>Using the reference date components 
                  the starting instants are <code>1972-12-31T08:00:00+09:00</code> and
                     <code>1972-12-31T17:00:00-06:00</code>, respectively, and normalize to
                     <code>1972-12-30T23:00:00Z</code> and <code>1972-12-31T23:00:00Z</code>.
               </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:time-equal(
  xs:time("21:30:00+10:30"),
  xs:time("06:00:00-05:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:time-equal(
  xs:time("24:00:00+01:00"),
  xs:time("00:00:00+01:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>This not the result one might expect. For <code>xs:dateTime</code>
                  values, a time of <code>24:00:00</code> is equivalent to <code>00:00:00</code> on
                  the following day. For <code>xs:time</code>, the normalization from
                     <code>24:00:00</code> to <code>00:00:00</code> happens before the
                     <code>xs:time</code> is converted into an <code>xs:dateTime</code> for the
                  purpose of the equality comparison. For <code>xs:time</code>, any operation on
                     <code>24:00:00</code> produces the same result as the same operation on
                     <code>00:00:00</code> because these are two different lexical representations
                  of the same value. </fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>-->
   <!--<fos:function name="time-less-than" prefix="op">
      <fos:signatures>
         <fos:proto name="time-less-than" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:time"/>
            <fos:arg name="arg2" type="xs:time"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="lt" types="xs:time numeric" other-operators="ge"
            >Defines the semantics
         of the <code>lt</code> operator when applied to two <code>xs:time</code> values. Also used in the
         definition of the <code>ge</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the first <code>xs:time</code> value represents an earlier
            instant in time than the second, when both are treated as being times on the same date,
            before adjusting the timezone.</p>
      </fos:summary>
      <fos:rules>
         <p>Each of the supplied <code>xs:time</code> values is expanded to an
               <code>xs:dateTime</code> value by associating the time with an arbitrary date. The
            function returns the result of comparing these two <code>xs:dateTime</code> values using
               <code>op:dateTime-less-than</code>.</p>
         <p>The result of the function is thus the same as the value of the expression:</p>
         <eg xml:space="preserve">op:dateTime-less-than(
        dateTime(xs:date('1972-12-31'), $arg1), 
        dateTime(xs:date('1972-12-31'), $arg2))</eg>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>.</p>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:time-less-than(
  xs:time("12:00:00"),
  xs:time("23:00:00+06:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:time-less-than(
  xs:time("11:00:00"),
  xs:time("17:00:00Z")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:time-less-than(
  xs:time("23:59:59"),
  xs:time("24:00:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
-->
   <!--<fos:function name="gYearMonth-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="gYearMonth-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:gYearMonth"/>
            <fos:arg name="arg2" type="xs:gYearMonth"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:gYearMonth numeric" other-operators="ne"
            >Defines the
         semantics of the <code>eq</code> operator when applied to two <code>xs:gYearMonth</code> values. Also
         used in the definition of the <code>ne</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the two <code>xs:gYearMonth</code> values have the same starting
            instant.</p>
      </fos:summary>
      <fos:rules>
         <p>The starting instants of <code>$arg1</code> and <code>$arg2</code> are calculated by
            supplying the missing components of <code>$arg1</code> and <code>$arg2</code> from the
               <code>xs:dateTime</code> template <code>xxxx-xx-01T00:00:00</code>. The function
            returns the result of comparing these two starting instants using
               <code>op:dateTime-equal</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>.</p>
         </fos:example>
         <fos:example>
            <p><code>op:gYearMonth-equal(xs:gYearMonth("1986-02"), xs:gYearMonth("1986-03"))</code>
               returns <code>false</code>. The starting instants are
                  <code>1986-02-01T00:00:00-05:00</code> and <code>1986-03-01T00:00:00</code>,
               respectively.</p>
         </fos:example>
         <fos:example>
            <p><code>op:gYearMonth-equal(xs:gYearMonth("1978-03"), xs:gYearMonth("1986-03Z"))</code>
               returns <code>false</code>. The starting instants are
                  <code>1978-03-01T00:00:00-05:00</code> and <code>1986-03-01T00:00:00Z</code>,
               respectively.</p>
         </fos:example>
      </fos:examples>
   </fos:function>-->
   <!--<fos:function name="gYear-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="gYear-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:gYear"/>
            <fos:arg name="arg2" type="xs:gYear"/>
         </fos:proto>
      </fos:signatures>

      <fos:opermap operator="eq" types="xs:gYear numeric" other-operators="ne"
            >Defines the semantics
         of the <code>eq</code> operator when applied to two <code>xs:gYear</code> values. Also used in the
         definition of the <code>ne</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the two <code>xs:gYear</code> values have the same starting instant.</p>
      </fos:summary>
      <fos:rules>
         <p>The starting instants of <code>$arg1</code> and <code>$arg2</code> are calculated by
            supplying the missing components of <code>$arg1</code> and <code>$arg2</code> from the
               <code>xs:dateTime</code> template <code>xxxx-01-01T00:00:00</code>. The function
            returns the result of comparing these two starting instants using
               <code>op:dateTime-equal</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>. Assume, also, that the <code>xs:dateTime</code> template is
                  <code>xxxx-01-01T00:00:00</code>. </p>
         </fos:example>
         <fos:example>
            <p><code>op:gYear-equal(xs:gYear("2005-12:00"), xs:gYear("2005+12:00"))</code> returns
                  <code>false</code>. The starting instants are
                  <code>2005-01-01T00:00:00-12:00</code> and <code>2005-01-01T00:00:00+12:00</code>,
               respectively, and normalize to <code>2005-01-01T12:00:00Z</code> and
                  <code>2004-12-31T12:00:00Z</code>.</p>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:gYear-equal(
  xs:gYear("1976-05:00"),
  xs:gYear("1976")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="gMonthDay-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="gMonthDay-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:gMonthDay"/>
            <fos:arg name="arg2" type="xs:gMonthDay"/>
         </fos:proto>
      </fos:signatures>

      <fos:opermap operator="eq" types="xs:gMonthDay numeric" other-operators="ne"
            >Defines the
         semantics of the <code>eq</code> operator when applied to two <code>xs:gMonthDay</code> values. Also
         used in the definition of the <code>ne</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the two <code>xs:gMonthDay</code> values have the same starting instant,
            when considered as days in the same year.</p>
      </fos:summary>
      <fos:rules>
         <p>The starting instants of <code>$arg1</code> and <code>$arg2</code> are calculated by
            supplying the missing components of <code>$arg1</code> and <code>$arg2</code> from the
               <code>xs:dateTime</code> template <code>1972-xx-xxT00:00:00</code> or an equivalent.
            The function returns the result of comparing these two starting instants using
               <code>op:dateTime-equal</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>. Assume for the purposes of illustration that the
                  <code>xs:dateTime</code> template used is <code>1972-xx-xxT00:00:00</code> (this
               does not affect the result). </p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:gMonthDay-equal(
  xs:gMonthDay("-\-12-25-14:00"),
  xs:gMonthDay("-\-12-26+10:00")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble> The starting instants are <code>1972-12-25T00:00:00-14:00</code> and
                     <code>1972-12-26T00:00:00+10:00</code>, respectively, and normalize to
                     <code>1972-12-25T14:00:00Z</code> and <code>1972-12-25T14:00:00Z</code>.
               </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:gMonthDay-equal(
  xs:gMonthDay("-\-12-25"),
  xs:gMonthDay("-\-12-26Z")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>-->
   <!--<fos:function name="gMonth-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="gMonth-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:gMonth"/>
            <fos:arg name="arg2" type="xs:gMonth"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:gMonth numeric" other-operators="ne"
            >Defines the
         semantics of the <code>eq</code> operator when applied to two <code>xs:gMonth</code> values. Also used
         in the definition of the <code>ne</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the two <code>xs:gMonth</code> values have the same starting instant,
            when considered as months in the same year.</p>
      </fos:summary>
      <fos:rules>
         <p>The starting instants of <code>$arg1</code> and <code>$arg2</code> are calculated by
            supplying the missing components of <code>$arg1</code> and <code>$arg2</code> from the
               <code>xs:dateTime</code> template <code>1972-xx-01T00:00:00</code> or an equivalent.
            The function returns the result of comparing these two starting instants using
               <code>op:dateTime-equal</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>. Assume, also, that the <code>xs:dateTime</code> template
               chosen is <code>1972-xx-01T00:00:00</code>. </p>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:gMonth-equal(
  xs:gMonth("-\-12-14:00"),
  xs:gMonth("-\-12+10:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble> The starting instants are <code>1972-12-01T00:00:00-14:00</code> and
                     <code>1972-12-01T00:00:00+10:00</code>, respectively, and normalize to
                     <code>1972-11-30T14:00:00Z</code> and <code>1972-12-01T14:00:00Z</code>.
               </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:gMonth-equal(
  xs:gMonth("-\-12"),
  xs:gMonth("-\-12Z")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>-->
   <!--<fos:function name="gDay-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="gDay-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:gDay"/>
            <fos:arg name="arg2" type="xs:gDay"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:gDay numeric" other-operators="ne"
            >Defines the semantics
         of the <code>eq</code> operator when applied to two <code>xs:gDay</code> values. Also used in the
         definition of the <code>ne</code> operator.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the two <code>xs:gDay</code> values have the same starting instant, when
            considered as days in the same month of the same year.</p>
      </fos:summary>
      <fos:rules>
         <p>The starting instants of <code>$arg1</code> and <code>$arg2</code> are calculated by
            supplying the missing components of <code>$arg1</code> and <code>$arg2</code> from the
               <code>xs:dateTime</code> template <code>1972-12-xxT00:00:00</code> or an equivalent.
            The function returns the result of comparing these two starting instants using
               <code>op:dateTime-equal</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>. Assume, also, that the <code>xs:dateTime</code> template is
                  <code>1972-12-xxT00:00:00</code>. </p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:gDay-equal(
  xs:gDay("-\-\-25-14:00"),
  xs:gDay("-\-\-25+10:00")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble> The starting instants are <code>1972-12-25T00:00:00-14:00</code> and
                     <code>1972-12-25T00:00:00+10:00</code>, respectively, and normalize to
                     <code>1972-12-25T14:00:00Z</code> and <code>1972-12-24T14:00:00Z</code>.
               </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:gDay-equal(
  xs:gDay("-\-\-12"),
  xs:gDay("-\-\-12Z")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>-->
   <fos:function name="year-from-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="year-from-dateTime" return-type="xs:integer?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the year component of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, or if the <code>year</code> component is absent, 
            the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> representing the year
            component in <code>$value</code>. The result may be negative.</p>
      </fos:rules>
      <fos:notes>
         <p>The value space for <code>xs:dateTime</code> allows year zero. XSD 1.0, however, does not
            allow year zero, so if a date earlier that 0001 CE was produced by validating
            an XML document using an XSD 1.0 processor, the results may be unpredictable.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-dateTime(
  xs:dateTime("1999-05-31T13:20:00-05:00")
)</eg></fos:expression>
               <fos:result>1999</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-dateTime(
  xs:dateTime("1999-05-31T21:30:00-05:00")
)</eg></fos:expression>
               <fos:result>1999</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-dateTime(
  xs:dateTime("1999-12-31T19:20:00")
)</eg></fos:expression>
               <fos:result>1999</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-dateTime(
  xs:dateTime("1999-12-31T24:00:00")
)</eg></fos:expression>
               <fos:result>2000</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-dateTime(
  xs:dateTime("-0002-06-06T00:00:00")
)</eg></fos:expression>
               <fos:result>-2</fos:result>
               <fos:postamble>The result is the same whether XSD 1.0 or 1.1 is in use, despite
                  the absence of a year 0 in the XSD 1.0 value space.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-dateTime(
  xs:gYearMonth("2007-05Z")
)</eg></fos:expression>
               <fos:result>2007</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-dateTime(
  xs:time("12:30:00")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1448" PR="1481" date="2024-10-08">
            <p>The function has been extended to handle other Gregorian types such as <code>xs:gYearMonth</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="month-from-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="month-from-dateTime" return-type="xs:integer?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the month component of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, or if it contains no <code>month</code> component,
            the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> between <code>1</code> and
            <code>12</code>, both inclusive, representing the month component in 
             <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>month-from-dateTime(
  xs:dateTime("1999-05-31T13:20:00-05:00")
)</eg></fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>month-from-dateTime(
  xs:dateTime("1999-12-31T19:20:00-05:00")
)</eg></fos:expression>
               <fos:result>12</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>month-from-dateTime(
  adjust-dateTime-to-timezone(
    xs:dateTime("1999-12-31T19:20:00-05:00"),
    xs:dayTimeDuration("PT0S")
  )
)</eg></fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>month-from-dateTime(
  xs:gYearMonth("2007-05Z")
)</eg></fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>month-from-dateTime(
  xs:time("12:30:00")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1448" PR="1481" date="2024-10-08">
            <p>The function has been extended to handle other Gregorian types such as <code>xs:gYearMonth</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="day-from-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="day-from-dateTime" return-type="xs:integer?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the day component of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, or if it contains no <code>day</code> component,
            the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> between <code>1</code> and
            <code>31</code>, both inclusive, representing the day component in the
            local value of <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>day-from-dateTime(
  xs:dateTime("1999-05-31T13:20:00-05:00")
)</eg></fos:expression>
               <fos:result>31</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>day-from-dateTime(
  xs:dateTime("1999-12-31T20:00:00-05:00")
)</eg></fos:expression>
               <fos:result>31</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>day-from-dateTime(
  adjust-dateTime-to-timezone(
    xs:dateTime("1999-12-31T19:20:00-05:00"),
    xs:dayTimeDuration("PT0S")
  )
)</eg></fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>day-from-dateTime(
  xs:gMonthDay("--05-31Z")
)</eg></fos:expression>
               <fos:result>31</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>day-from-dateTime(
  xs:time("12:30:00")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1448" PR="1481" date="2024-10-08">
            <p>The function has been extended to handle other Gregorian types such as <code>xs:gMonthDay</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="hours-from-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="hours-from-dateTime" return-type="xs:integer?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the hours component of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, or if it contains no <code>hours</code>
            component, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> between <code>0</code> and
            <code>23</code>, both inclusive, representing the hours component in <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-dateTime(
  xs:dateTime("1999-05-31T08:20:00-05:00")
)</eg></fos:expression>
               <fos:result>8</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-dateTime(
  xs:dateTime("1999-12-31T21:20:00-05:00")
)</eg></fos:expression>
               <fos:result>21</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-dateTime(
  adjust-dateTime-to-timezone(
    xs:dateTime("1999-12-31T21:20:00-05:00"),
    xs:dayTimeDuration("PT0S")
  )
)</eg></fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-dateTime(
  xs:dateTime("1999-12-31T12:00:00")
)</eg></fos:expression>
               <fos:result>12</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-dateTime(
  xs:dateTime("1999-12-31T24:00:00")
)</eg></fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-dateTime(
  xs:gYearMonth("2007-05Z")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-dateTime(
  xs:time("12:30:00")
)</eg></fos:expression>
               <fos:result>12</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>

      <fos:changes>
         <fos:change issue="1448" PR="1481" date="2024-10-08">
            <p>The function has been extended to handle other types including <code>xs:time</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="minutes-from-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="minutes-from-dateTime" return-type="xs:integer?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the minute component of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, or if it contains no <code>minutes</code>
            component, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> value between <code>0</code>
            and <code>59</code>, both inclusive, representing the minute component in the local value of
            <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>minutes-from-dateTime(
  xs:dateTime("1999-05-31T13:20:00-05:00")
)</eg></fos:expression>
               <fos:result>20</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>minutes-from-dateTime(
  xs:dateTime("1999-05-31T13:30:00+05:30")
)</eg></fos:expression>
               <fos:result>30</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>minutes-from-dateTime(
  xs:gYearMonth("2007-05Z")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>minutes-from-dateTime(
  xs:time("12:30:00")
)</eg></fos:expression>
               <fos:result>30</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1448" PR="1481" date="2024-10-08">
            <p>The function has been extended to handle other types including <code>xs:time</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="seconds-from-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="seconds-from-dateTime" return-type="xs:decimal?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the seconds component of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, or if it contains no <code>seconds</code>
            component, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:decimal</code> value greater than or equal
            to zero and less than 60, representing the seconds and fractional seconds in <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds-from-dateTime(
  xs:dateTime("1999-05-31T13:20:00-05:00")
)</eg></fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds-from-dateTime(
  xs:gYearMonth("2007-05Z")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>seconds-from-dateTime(
  xs:time("12:30:14.5")
)</eg></fos:expression>
               <fos:result>14.5</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="timezone-from-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="timezone-from-dateTime" return-type="xs:dayTimeDuration?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the timezone component of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns the timezone component of <code>$value</code>, if any. If
            <code>$value</code> has a timezone component, then the result is an
               <code>xs:dayTimeDuration</code> that indicates deviation from UTC; its value may
            range from +14:00 to -14:00 hours, both inclusive. If <code>$value</code> has no timezone
            component, the result is the empty sequence.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>timezone-from-dateTime(
  xs:dateTime("1999-05-31T13:20:00-05:00")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("-PT5H")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>timezone-from-dateTime(
  xs:dateTime("2000-06-12T13:20:00Z")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("PT0S")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>timezone-from-dateTime(
  xs:dateTime("2004-08-27T00:00:00")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>timezone-from-dateTime(
  xs:gYearMonth("2007-05Z")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("PT0S")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>timezone-from-dateTime(
  xs:time("12:30:00")
)</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1448" PR="1481" date="2024-10-08">
            <p>The function has been extended to handle other types such as <code>xs:gYearMonth</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="parts-of-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="parts-of-dateTime" return-type-ref="dateTime-record" return-type-ref-occurs="?">
            <fos:arg name="value" type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns all the components of a <termref def="dt-gregorian"/> value.</p>
      </fos:summary>
      
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns a record whose fields are as follows. All entries will be present,
         even when the value is an empty sequence.</p>
         <table>
            <thead>
               <tr>
                  <th>Key</th>
                  <th>Value</th>
               </tr>
            </thead>
            <tbody>
               <tr>
                  <td><code>year</code></td>
                  <td>Generally, the value of <code>fn:year-from-dateTime($value)</code>: but
                  see the notes below regarding negative years.</td>
               </tr>
               <tr>
                  <td><code>month</code></td>
                  <td>The value of <code>fn:month-from-dateTime($value)</code></td>
               </tr>
               <tr>
                  <td><code>day</code></td>
                  <td>The value of <code>fn:day-from-dateTime($value)</code></td>
               </tr>
               <tr>
                  <td><code>hours</code></td>
                  <td>The value of <code>fn:hours-from-dateTime($value)</code></td>
               </tr>
               <tr>
                  <td><code>minutes</code></td>
                  <td>The value of <code>fn:minutes-from-dateTime($value)</code></td>
               </tr>
               <tr>
                  <td><code>seconds</code></td>
                  <td>The value of <code>fn:seconds-from-dateTime($value)</code></td>
               </tr>
               <tr>
                  <td><code>timezone</code></td>
                  <td>The value of <code>fn:timezone-from-dateTime($value)</code></td>
               </tr>              
            </tbody>
         </table>
         <p>The range of years supported is <termref def="implementation-defined"/>. If years earlier than
         0001 CE are supported, however, the year number returned by this function 
         follows the proleptic Gregorian calendar as defined
         in ISO 8601. This means that the year before 0001 CE is numbered zero, and the year before that
         is numbered -1.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>parts-of-dateTime(
  xs:dateTime("1999-05-31T13:20:00-05:00")
)</eg></fos:expression>
               <fos:result><eg>{ "year": 1999, "month": 5, "day": 31, 
  "hours": 13, "minutes": 20, "seconds": 0, 
  "timezone": xs:dayTimeDuration("-PT5H") }</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>parts-of-dateTime(
  xs:time("13:30:04.2678")
)</eg></fos:expression>
               <fos:result><eg>{ "year": (), "month": (), "day": (), 
  "hours": 13, "minutes": 30, "seconds": 4.2678, 
  "timezone": () }</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>parts-of-dateTime(
  xs:gYearMonth("2007-05Z")
)</eg></fos:expression>
               <fos:result><eg>{ "year": 2007, "month": 5, "day": (), 
  "hours": (), "minutes": (), "seconds": (), 
  "timezone": xs:dayTimeDuration("PT0S") }</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change>
            <p>New in 4.0</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="build-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="build-dateTime" return-type="(xs:dateTime | xs:date | xs:time | xs:gYear | xs:gYearMonth | xs:gMonth | xs:gMonthDay | xs:gDay)?">
            <fos:arg name="value" type-ref="dateTime-record" type-ref-occurs="?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Constructs a <termref def="dt-gregorian"/> value from the values of its components.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns a <termref def="dt-gregorian"/> value based on the supplied component
            values. The result will be the <termref def="dt-gregorian"/> value <code>$R</code> such that
            <code>deep-equal( $significant(parts-of-dateTime($R)), $significant($value) )</code>,
            where <code>$significant</code> is the function <code>map:filter(?, fn($K, $V){$K eq "timezone" or exists($V)})</code>,
         that is, a function that discards entries in a map whose value is the empty sequence, other than the entry
         with key <code>"timezone"</code>.</p>
         <p>If all seven components are present (year, month, day, hours, minutes, seconds, and timezone)
         then the result will be of type <code>xs:dateTimeStamp</code>.</p>
         <p>The range of years supported is <termref def="implementation-defined"/>. If years earlier than
         0001 CE are supported then the numbering follows the proleptic Gregorian calendar as defined
         in ISO 8601. This means that the year before 0001 CE is numbered zero, and the year before that
         is numbered -1.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DT" code="0005"/> if the set of fields
         that are present and non-empty in <code>$value</code> is not one of the sets:</p>
         <ulist>
            <item><p>year, month, day, hours, minutes, seconds, and optional timezone (delivering an <code>xs:dateTime</code>)</p></item>
            <item><p>year, month, day, and optional timezone (delivering an <code>xs:date</code>)</p></item>
            <item><p>year, and optional timezone (delivering an <code>xs:gYear</code>)</p></item>
            <item><p>year, month, and optional timezone (delivering an <code>xs:gYearMonth</code>)</p></item>
            <item><p>month, and optional timezone (delivering an <code>xs:gMonth</code>)</p></item>
            <item><p>month, day, and optional timezone (delivering an <code>xs:gMonthDay</code>)</p></item>
            <item><p>day, and optional timezone (delivering an <code>xs:gDay</code>)</p></item>
            <item><p>hours, minutes, seconds, and optional timezone (delivering an <code>xs:time</code>)</p></item>
         </ulist>
         <p>A dynamic error is raised <errorref class="DT" code="0006"/> if any of the
            components in <code>$value</code> is outside the permitted range
            (for example if the value of the <code>minutes</code> component is less than zero or
            greater than 59, or if the timezone is outside the range <code>-PT14H</code> to <code>PT14H</code>), 
            or if the combination of fields is not a valid date/time (for example,
            if <code>month</code> is 4 and <code>day</code> is 31).</p>
      </fos:errors>
      <fos:notes>
         <p>Components that are present in <code>$value</code> but with an empty value are treated
         as if they were absent.</p>
         <p>The timezone, if present, must correspond to an integral number of minutes in the range
         -840 to +840.</p>
         <p>Midnight must be expressed with the <code>hours</code> value set to zero, not 24.</p>
         <p>The standard <xtermref spec="XP40" ref="dt-coercion-rules"/> apply, so (for example) the integral 
         components may be supplied as <code>xs:double</code> values, and the timezone may be
         supplied as an <code>xs:duration</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
build-dateTime({
  "year": 1999,
  "month": 5,
  "day": 31, 
  "hours": 13,
  "minutes": 20,
  "seconds": 0, 
  "timezone": xs:dayTimeDuration("-PT5H")
})</eg></fos:expression>
               <fos:result><eg>xs:dateTime("1999-05-31T13:20:00-05:00")</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>build-dateTime({ "hours": 13, "minutes": 30, "seconds": 4.2678 })</eg></fos:expression>
               <fos:result><eg>xs:time("13:30:04.2678")</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
build-dateTime({ "year": 2007, "month": 5, "timezone": xs:dayTimeDuration("PT0S") })</eg></fos:expression>
               <fos:result><eg>xs:gYearMonth("2007-05Z")</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change>
            <p>New in 4.0</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="year-from-date" prefix="fn">
      <fos:signatures>
         <fos:proto name="year-from-date" return-type="xs:integer?">
            <fos:arg name="value" type="xs:date?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the year component of an <code>xs:date</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> representing the year in the
            local value of <code>$value</code>. The value may be negative. </p>
      </fos:rules>
      <fos:notes>
         <p>The value space for <code>xs:date</code> allows year zero. XSD 1.0, however, does not
            allow year zero, so if a date earlier that 0001 CE was produced by validating
            an XML document using an XSD 1.0 processor, the results may be unpredictable.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-date(
  xs:date("1999-05-31")
)</eg></fos:expression>
               <fos:result>1999</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-date(
  xs:date("2000-01-01+05:00")
)</eg></fos:expression>
               <fos:result>2000</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>year-from-date(
  xs:date("-0002-06-01")
)</eg></fos:expression>
               <fos:result>-2</fos:result>
               <fos:postamble>The result is the same whether XSD 1.0 or 1.1 is in use, despite
               the absence of a year 0 in the XSD 1.0 value space.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="month-from-date" prefix="fn">
      <fos:signatures>
         <fos:proto name="month-from-date" return-type="xs:integer?">
            <fos:arg name="value" type="xs:date?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the month component of an <code>xs:date</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> between
            <code>1</code> and <code>12</code>, both
            inclusive, representing the month component in the local value of <code>$value</code>.
         </p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>month-from-date(
  xs:date("1999-05-31-05:00")
)</eg></fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>month-from-date(
  xs:date("2000-01-01+05:00")
)</eg></fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="day-from-date" prefix="fn">
      <fos:signatures>
         <fos:proto name="day-from-date" return-type="xs:integer?">
            <fos:arg name="value" type="xs:date?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the day component of an <code>xs:date</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> between
            <code>1</code> and <code>31</code>, both
            inclusive, representing the day component in the localized value of
            <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>day-from-date(
  xs:date("1999-05-31-05:00")
)</eg></fos:expression>
               <fos:result>31</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>day-from-date(
  xs:date("2000-01-01+05:00")
)</eg></fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="timezone-from-date" prefix="fn">
      <fos:signatures>
         <fos:proto name="timezone-from-date" return-type="xs:dayTimeDuration?">
            <fos:arg name="value" type="xs:date?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the timezone component of an <code>xs:date</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns the timezone component of <code>$value</code>, if any. If
            <code>$value</code> has a timezone component, then the result is an
               <code>xs:dayTimeDuration</code> that indicates deviation from UTC; its value may
            range from +14:00 to -14:00 hours, both inclusive. If <code>$value</code> has no timezone
            component, the result is the empty sequence.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>timezone-from-date(
  xs:date("1999-05-31-05:00")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("-PT5H")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>timezone-from-date(
  xs:date("2000-06-12Z")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("PT0S")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="hours-from-time" prefix="fn">
      <fos:signatures>
         <fos:proto name="hours-from-time" return-type="xs:integer?">
            <fos:arg name="value" type="xs:time?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the hours component of an <code>xs:time</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> between
            <code>0</code> and <code>23</code>, both
            inclusive, representing the value of the hours component in the local value of
            <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>. </p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>hours-from-time(xs:time("11:23:00"))</fos:expression>
               <fos:result>11</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>hours-from-time(xs:time("21:23:00"))</fos:expression>
               <fos:result>21</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>hours-from-time(xs:time("01:23:00+05:00"))</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>hours-from-time(
  adjust-time-to-timezone(
    xs:time("01:23:00+05:00"),
    xs:dayTimeDuration("PT0S")
  )
)</eg></fos:expression>
               <fos:result>20</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>hours-from-time(xs:time("24:00:00"))</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="minutes-from-time" prefix="fn">
      <fos:signatures>
         <fos:proto name="minutes-from-time" return-type="xs:integer?">
            <fos:arg name="value" type="xs:time?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the minutes component of an <code>xs:time</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:integer</code> value between <code>0</code>
            and <code>59</code>, both inclusive, representing the value of the minutes component
            in the local value of <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>minutes-from-time(xs:time("13:00:00Z"))</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="seconds-from-time" prefix="fn">
      <fos:signatures>
         <fos:proto name="seconds-from-time" return-type="xs:decimal?">
            <fos:arg name="value" type="xs:time?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the seconds component of an <code>xs:time</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:decimal</code> value greater than or equal
            to zero and less than 60, representing the seconds and fractional seconds in the local
            value of <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>seconds-from-time(xs:time("13:20:10.5"))</fos:expression>
               <fos:result>10.5</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="timezone-from-time" prefix="fn">
      <fos:signatures>
         <fos:proto name="timezone-from-time" return-type="xs:dayTimeDuration?">
            <fos:arg name="value" type="xs:time?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the timezone component of an <code>xs:time</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns the timezone component of <code>$value</code>, if any. If
            <code>$value</code> has a timezone component, then the result is an
               <code>xs:dayTimeDuration</code> that indicates deviation from UTC; its value may
            range from +14:00 to -14:00 hours, both inclusive. If <code>$value</code> has no timezone
            component, the result is the empty sequence.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>timezone-from-time(xs:time("13:20:00-05:00"))</fos:expression>
               <fos:result>xs:dayTimeDuration("-PT5H")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>timezone-from-time(xs:time("13:20:00"))</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="adjust-dateTime-to-timezone" prefix="fn">
      <fos:signatures>
         <fos:proto name="adjust-dateTime-to-timezone" return-type="xs:dateTime?">
            <fos:arg name="value" type="xs:dateTime?"/>
            <fos:arg name="timezone" type="xs:dayTimeDuration?" default="fn:implicit-timezone()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Adjusts an <code>xs:dateTime</code> value to a specific timezone, or to no timezone at
            all.</p>
      </fos:summary>
      <fos:rules>
         <p> If <code>$value</code> is the empty sequence, then the function returns the empty
            sequence.</p>
         <p> If <code>$value</code> does not have a timezone component and <code>$timezone</code> is
            the empty sequence, then the result is <code>$value</code>.</p>
         <p> If <code>$value</code> does not have a timezone component and <code>$timezone</code> is
            not the empty sequence, then the result is <code>$value</code> with <code>$timezone</code>
            as the timezone component.</p>
         <p> If <code>$value</code> has a timezone component and <code>$timezone</code> is the empty
            sequence, then the result is the local value of <code>$value</code> without its timezone
            component.</p>
         <p> If <code>$value</code> has a timezone component and <code>$timezone</code> is not the
            empty sequence, then the result is the <code>xs:dateTime</code> value that is equal to
            <code>$value</code> and that has a timezone component equal to
            <code>$timezone</code>.</p>
      </fos:rules>
      <fos:errors>
         <p> A dynamic error is raised <errorref class="DT" code="0003"
               /> if <code>$timezone</code>
            is less than <code>-PT14H</code> or greater than <code>PT14H</code> or is not an
            integral number of minutes.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p> Assume the dynamic context provides an implicit timezone of <code>-05:00
                  (-PT5H0M)</code>.</p>
         </fos:example>
         <fos:variable name="tz-10" id="v-adjust-dateTime-to-timezone-tz10"
            select="xs:dayTimeDuration(&quot;-PT10H&quot;)"/>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T10:00:00')
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-07T10:00:00-05:00')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-adjust-dateTime-to-timezone-tz10">
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T10:00:00-07:00')
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-07T12:00:00-05:00')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-adjust-dateTime-to-timezone-tz10">
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T10:00:00'),
  $tz-10
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-07T10:00:00-10:00')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-adjust-dateTime-to-timezone-tz10">
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T10:00:00-07:00'),
  $tz-10
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-07T07:00:00-10:00')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T10:00:00-07:00'),
  xs:dayTimeDuration("PT10H")
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-08T03:00:00+10:00')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T00:00:00+01:00'),
  xs:dayTimeDuration("-PT8H")
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-06T15:00:00-08:00')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T10:00:00'),
  ()
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-07T10:00:00')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-dateTime-to-timezone(
  xs:dateTime('2002-03-07T10:00:00-07:00'),
  ()
)</eg></fos:expression>
               <fos:result>xs:dateTime('2002-03-07T10:00:00')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="adjust-date-to-timezone" prefix="fn">
      <fos:signatures>
         <fos:proto name="adjust-date-to-timezone" return-type="xs:date?">
            <fos:arg name="value" type="xs:date?"/>
            <fos:arg name="timezone" type="xs:dayTimeDuration?" default="fn:implicit-timezone()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Adjusts an <code>xs:date</code> value to a specific timezone, or to no timezone at all;
            the result is the date in the target timezone that contains the starting instant of the
            supplied date.</p>
      </fos:summary>
      <fos:rules>
         <p> If <code>$value</code> is the empty sequence, then the function returns the empty
            sequence.</p>
         <p> If <code>$value</code> does not have a timezone component and <code>$timezone</code> is
            the empty sequence, then the result is <code>$value</code>.</p>
         <p> If <code>$value</code> does not have a timezone component and <code>$timezone</code> is
            not the empty sequence, then the result is <code>$value</code> with <code>$timezone</code>
            as the timezone component.</p>
         <p> If <code>$value</code> has a timezone component and <code>$timezone</code> is the empty
            sequence, then the result is the local value of <code>$value</code> without its timezone
            component.</p>
         <p> If <code>$value</code> has a timezone component and <code>$timezone</code> is not the
            empty sequence, then:</p>
         <ulist>
            <item>
               <p>Let <code>$dt</code> be the value of <code>fn:dateTime($arg,
                     xs:time('00:00:00'))</code>.</p>
            </item>
            <item>
               <p>Let <code>$adt</code> be the value of <code>fn:adjust-dateTime-to-timezone($dt,
                     $timezone)</code></p>
            </item>
            <item>
               <p>The function returns the value of <code>xs:date($adt)</code></p>
            </item>
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DT" code="0003"
               /> if <code>$timezone</code>
            is less than <code>-PT14H</code> or greater than <code>PT14H</code> or is not an
            integral number of minutes.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>Assume the dynamic context provides an implicit timezone of <code>-05:00
                  (-PT5H0M)</code>.</p>
         </fos:example>
         <fos:variable id="v-adjust-date-to-timezone-tz10" name="tz-10"
            select="xs:dayTimeDuration(&quot;-PT10H&quot;)"/>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>adjust-date-to-timezone(
  xs:date("2002-03-07")
)</eg></fos:expression>
               <fos:result>xs:date("2002-03-07-05:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>adjust-date-to-timezone(
  xs:date("2002-03-07-07:00")
)</eg></fos:expression>
               <fos:result>xs:date("2002-03-07-05:00")</fos:result>
               <fos:postamble><code>$value</code> is converted to
                     <code>xs:dateTime("2002-03-07T00:00:00-07:00")</code>. This is adjusted to the
                  implicit timezone, giving <code>"2002-03-07T02:00:00-05:00"</code>.
               </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-adjust-date-to-timezone-tz10">
               <fos:expression><eg>adjust-date-to-timezone(
  xs:date("2002-03-07"),
  $tz-10
)</eg></fos:expression>
               <fos:result>xs:date("2002-03-07-10:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-adjust-date-to-timezone-tz10">
               <fos:expression><eg>adjust-date-to-timezone(
  xs:date("2002-03-07-07:00"),
  $tz-10
)</eg></fos:expression>
               <fos:result>xs:date("2002-03-06-10:00")</fos:result>
               <fos:postamble><code>$value</code> is converted to
                  <code>xs:dateTime("2002-03-07T00:00:00-07:00")</code>.
                  This is adjusted to the given timezone,
                  giving <code>"2002-03-06T21:00:00-10:00"</code>. </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-date-to-timezone(
  xs:date("2002-03-07"),
  ()
)</eg></fos:expression>
               <fos:result>xs:date("2002-03-07")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-date-to-timezone(
  xs:date("2002-03-07-07:00"),
  ()
)</eg></fos:expression>
               <fos:result>xs:date("2002-03-07")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="adjust-time-to-timezone" prefix="fn">
      <fos:signatures>
         <fos:proto name="adjust-time-to-timezone" return-type="xs:time?">
            <fos:arg name="value" type="xs:time?"/>
            <fos:arg name="timezone" type="xs:dayTimeDuration?" default="fn:implicit-timezone()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Adjusts an <code>xs:time</code> value to a specific timezone, or to no timezone at
            all.</p>
      </fos:summary>
      <fos:rules>
         <p> If <code>$value</code> is the empty sequence, then the function returns the empty
            sequence.</p>
         <p> If <code>$value</code> does not have a timezone component and <code>$timezone</code> is
            the empty sequence, then the result is <code>$value</code>.</p>
         <p> If <code>$value</code> does not have a timezone component and <code>$timezone</code> is
            not the empty sequence, then the result is <code>$value</code> with <code>$timezone</code>
            as the timezone component.</p>
         <p> If <code>$value</code> has a timezone component and <code>$timezone</code> is the empty
            sequence, then the result is the localized value of <code>$value</code> without its
            timezone component.</p>
         <p> If <code>$value</code> has a timezone component and <code>$timezone</code> is not the
            empty sequence, then:</p>
         <ulist>
            <item>
               <p>Let <code>$dt</code> be the <code>xs:dateTime</code> value
                  <code>fn:dateTime(xs:date('1972-12-31'), $value)</code>.</p>
            </item>
            <item>
               <p>Let <code>$adt</code> be the value of <code>fn:adjust-dateTime-to-timezone($dt,
                     $timezone)</code>
               </p>
            </item>
            <item>
               <p>The function returns the <code>xs:time</code> value
                  <code>xs:time($adt)</code>.</p>
            </item>
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DT" code="0003"
               /> if <code>$timezone</code>
            is less than <code>-PT14H</code> or greater than <code>PT14H</code> or if does not
            contain an integral number of minutes.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>Assume the dynamic context provides an implicit timezone of <code>-05:00
                  (-PT5H0M)</code>.</p>
         </fos:example>
         <fos:variable id="v-adjust-time-to-timezone-tz10" name="tz-10"
            select="xs:dayTimeDuration(&quot;-PT10H&quot;)"/>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>adjust-time-to-timezone(
  xs:time("10:00:00")
)</eg></fos:expression>
               <fos:result>xs:time("10:00:00-05:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-time-to-timezone(
  xs:time("10:00:00-07:00")
)</eg></fos:expression>
               <fos:result>xs:time("12:00:00-05:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-adjust-time-to-timezone-tz10">
               <fos:expression><eg>adjust-time-to-timezone(
  xs:time("10:00:00"),
  $tz-10
)</eg></fos:expression>
               <fos:result>xs:time("10:00:00-10:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-adjust-time-to-timezone-tz10">
               <fos:expression><eg>adjust-time-to-timezone(
  xs:time("10:00:00-07:00"),
  $tz-10
)</eg></fos:expression>
               <fos:result>xs:time("07:00:00-10:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-time-to-timezone(
  xs:time("10:00:00"),
  ()
)</eg></fos:expression>
               <fos:result>xs:time("10:00:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-time-to-timezone(
  xs:time("10:00:00-07:00"),
  ()
)</eg></fos:expression>
               <fos:result>xs:time("10:00:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-time-to-timezone(
  xs:time("10:00:00-07:00"),
  xs:dayTimeDuration("PT10H")
)</eg></fos:expression>
               <fos:result>xs:time("03:00:00+10:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="civil-timezone" prefix="fn">
      <fos:signatures>
         <fos:proto name="civil-timezone" return-type="xs:dayTimeDuration">
            <fos:arg name="value" type="xs:dateTime"/>
            <fos:arg name="place" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="default-place">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the timezone offset from UTC that is in conventional use at a given place and time.</p>
      </fos:summary>
      <fos:rules>
         <p>This function uses a database of civil timezones (including daylight savings time) to return
         the timezone offset for a given date/time and place. For example, the timezone offset for New York
         on 31 December 2024 would be <code>-PT5H</code>.</p>
         <p>If the <code>$place</code> argument is empty then the
         <xtermref spec="XP40" ref="dt-default-place"/> from the dynamic context is used.</p>
         <p>If the supplied <code>$value</code> has no timezone then the implicit timezone from the dynamic
         context is used. This is unrelated to the timezone applicable to the requested <code>$place</code>.</p>
         <p>The intended use of the <code>$place</code> argument is to identify
 the place where an event
represented by the <code>$value</code> argument took place or will take place.
                  The value must be an IANA timezone name as defined in the IANA timezone database <bibref ref="olson"/>.
   Examples are <code>"America/New_York"</code> and <code>"Europe/Rome"</code>.</p>

<p>The result of the function is the civil timezone offset applicable to the given date/time
   and place, as determined by the IANA timezone database or an alternative authoritative source.</p>
      </fos:rules>
      <fos:errors>
         <p> A dynamic error is raised <errorref class="DT" code="0004"
               /> if no timezone information is available for the given date/time and place.
         This includes the case where the given place is not present in the timezone database,
         and also the case where the information available for that place does not cover a sufficient range
         of dates.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>civil-timezone(
  xs:dateTime('2024-12-31T23:59:59'), 'America/New_York')
</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('-PT5H')</fos:result>
            </fos:test>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>civil-timezone(
  xs:dateTime('2024-06-30T23:59:59'), 'America/New_York')
</eg></fos:expression>
               <fos:result>xs:dayTimeDuration('-PT4H')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>adjust-dateTime-to-timezone(
  current-dateTime(),
  civil-timezone(current-dateTime(), 'America/New_York')
)</eg></fos:expression>
               <fos:result narrative="true">The current civil date and time in New York.</fos:result>
            </fos:test>

         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>civil-timezone(xs:dateTime('2024-07-01T09:00:00'))</fos:expression>
               <fos:result narrative="true">If the default place is a location in the same timezone 
                  as (say) Paris, then <code>PT2H</code></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1539" PR="1545" date="2024-11-05"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="subtract-dateTimes" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-dateTimes" return-type="xs:dayTimeDuration">
            <fos:arg name="arg1" type="xs:dateTime"/>
            <fos:arg name="arg2" type="xs:dateTime"/>
         </fos:proto>
      </fos:signatures>

      <fos:opermap operator="-" types="xs:dateTime numeric"
            >Defines the semantics of the <code>-</code>
         operator when applied to two <code>xs:dateTime</code> values.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an <code>xs:dayTimeDuration</code> representing the amount of elapsed time
            between the instants <code>arg2</code> and <code>arg1</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If either <code>$arg1</code> or <code>$arg2</code> do not contain an explicit timezone
            then, for the purpose of the operation, the implicit timezone provided by the dynamic
            context (See <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"
            />.) is
            assumed to be present as part of the value.</p>
         <p>The function returns the elapsed time between the date/time instant <code>arg2</code>
            and the date/time instant <code>arg1</code>, computed according to the algorithm given
            in Appendix E of <bibref
               ref="xmlschema-2"
               />, and expressed as a
               <code>xs:dayTimeDuration</code>.</p>
         <p>If the normalized value of <code>$arg1</code> precedes in time the normalized value of
               <code>$arg2</code>, then the returned value is a negative duration.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>.</p>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:subtract-dateTimes(
  xs:dateTime("2000-10-30T06:12:00"),
  xs:dateTime("1999-11-28T09:00:00Z")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("P337DT2H12M")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-dates" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-dates" return-type="xs:dayTimeDuration">
            <fos:arg name="arg1" type="xs:date"/>
            <fos:arg name="arg2" type="xs:date"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:date numeric"
            >Defines the semantics of the <code>-</code> operator
         when applied to two <code>xs:date</code> values.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:dayTimeDuration</code> that corresponds to the elapsed time between
            the starting instant of <code>$arg2</code> and the starting instant of
               <code>$arg2</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If either <code>$arg1</code> or <code>$arg2</code> do not contain an explicit timezone
            then, for the purpose of the operation, the implicit timezone provided by the dynamic
            context (See <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"
            />.) is
            assumed to be present as part of the value.</p>
         <p>The starting instant of an <code>xs:date</code> is the <code>xs:dateTime</code> at
               <code>00:00:00</code> on that date. </p>
         <p>The function returns the result of subtracting the two starting instants using
               <code>op:subtract-dateTimes</code>.</p>
         <p>If the starting instant of <code>$arg1</code> precedes in time the starting instant of
               <code>$arg2</code>, then the returned value is a negative duration.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
               <code>Z</code>. </p>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="PT0S">
               <fos:expression><eg>op:subtract-dates(
  xs:date("2000-10-30"),
  xs:date("1999-11-28")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("P337D")</fos:result>
               <fos:postamble>The normalized values of the two starting instants are <code>{ 2000,
                  10, 30, 0, 0, 0, xs:dayTimeDuration("PT0S") }</code> and <code>{ 1999, 11, 28, 0, 0, 0,
                     xs:dayTimeDuration("PT0S") }</code>.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Now assume that the dynamic context provides an implicit timezone value of
                  <code>+05:00</code>.</p>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="PT5H">
               <fos:expression><eg>op:subtract-dates(
  xs:date("2000-10-30"),
  xs:date("1999-11-28Z")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("P336DT19H")</fos:result>
               <fos:postamble> The normalized values of the two starting instants are <code>{ 2000,
                  10, 29, 19, 0, 0, xs:dayTimeDuration("PT0S") }</code> and <code>{ 1999, 11, 28, 0, 0, 0,
                     xs:dayTimeDuration("PT0S") }</code>.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-dates(
  xs:date("2000-10-15-05:00"),
  xs:date("2000-10-10+02:00")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("P5DT7H")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-times" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-times" return-type="xs:dayTimeDuration">
            <fos:arg name="arg1" type="xs:time"/>
            <fos:arg name="arg2" type="xs:time"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:time numeric"
            >Defines the semantics of the <code>-</code> operator
         when applied to two <code>xs:time</code> values.</fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:dayTimeDuration</code> that corresponds to the elapsed time between
            the values of <code>$arg2</code> and <code>$arg1</code> treated as times on the same
            date.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of the expression:</p>
         <eg xml:space="preserve">op-subtract-dateTimes(
        dateTime(xs:date('1972-12-31'), $arg1),
        dateTime(xs:date('1972-12-31'), $arg2))</eg>
      </fos:rules>
      <fos:notes>
         <p>Any other reference date would work equally well.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>Assume that the dynamic context provides an implicit timezone value of
                  <code>-05:00</code>. Assume, also, that the date components of the reference
                  <code>xs:dateTime</code> correspond to <code>"1972-12-31"</code>.</p>
         </fos:example>
         <fos:example>
            <fos:test implicit-timezone="-PT5H">
               <fos:expression><eg>op:subtract-times(
  xs:time("11:12:00Z"),
  xs:time("04:00:00")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("PT2H12M")</fos:result>
               <fos:postamble>This is obtained by subtracting from the <code>xs:dateTime</code>
                  value <code>{ 1972, 12, 31, 11, 12, 0, xs:dayTimeDuration("PT0S") }</code> the <code>xs:dateTime</code>
                  value <code>{ 1972, 12, 31, 9, 0, 0, xs:dayTimeDuration("PT0S") }</code>.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-times(
  xs:time("11:00:00-05:00"),
  xs:time("21:30:00+05:30")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("PT0S")</fos:result>
               <fos:postamble>The two <code>xs:dateTime</code> values are <code>{ 1972, 12, 31, 11,
                  0, 0, xs:dayTimeDuration("-PT5H") }</code> and <code>{ 1972, 12, 31, 21, 30, 0, xs:dayTimeDuration("PT5H30M") }</code>. These
                  normalize to <code>{ 1972, 12, 31, 16, 0, 0, xs:dayTimeDuration("PT0S") }</code>
                  and <code>{ 1972, 12, 31, 16, 0, 0, xs:dayTimeDuration("PT0S") }</code>.
               </fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-times(
  xs:time("17:00:00-06:00"),
  xs:time("08:00:00+09:00")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("P1D")</fos:result>
               <fos:postamble>The two normalized <code>xs:dateTime</code> values are <code>{ 1972,
                  12, 31, 23, 0, 0, xs:dayTimeDuration("PT0S") }</code> and <code>{ 1972, 12, 30, 23, 0, 0,
                     xs:dayTimeDuration("PT0S") }</code>.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-times(
  xs:time("24:00:00"),
  xs:time("23:59:59")
)</eg></fos:expression>
               <fos:result>xs:dayTimeDuration("-PT23H59M59S")</fos:result>
               <fos:postamble>The two normalized <code>xs:dateTime</code> values are <code>{ 1972,
                     12, 31, 0, 0, 0, () }</code> and <code>{ 1972, 12, 31, 23, 59, 59.0,
                  () }</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="add-yearMonthDuration-to-dateTime" prefix="op">
      <fos:signatures>
         <fos:proto name="add-yearMonthDuration-to-dateTime" return-type="xs:dateTime">
            <fos:arg name="arg1" type="xs:dateTime"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="xs:dateTime xs:yearMonthDuration numeric"
            >Defines the
         semantics of the <code>+</code> operator when applied to an <code>xs:dateTime</code> and an
            <code>xs:yearMonthDuration</code> value. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:dateTime</code> that is a given duration after a specified
               <code>xs:dateTime</code> (or before, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of adding <code>$arg2</code> to the value of
               <code>$arg1</code> using the algorithm described in Appendix E of <bibref
               ref="xmlschema-2"
               />, disregarding the rule about leap seconds. If <code>$arg2</code>
            is negative, then the result <code>xs:dateTime</code> precedes <code>$arg1</code>.</p>
         <p>The result has the same timezone as <code>$arg1</code>. If <code>$arg1</code> has no
            timezone, the result has no timezone. </p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-yearMonthDuration-to-dateTime(
  xs:dateTime("2000-10-30T11:12:00"),
  xs:yearMonthDuration("P1Y2M")
)</eg></fos:expression>
               <fos:result>xs:dateTime("2001-12-30T11:12:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="add-dayTimeDuration-to-dateTime" prefix="op">
      <fos:signatures>
         <fos:proto name="add-dayTimeDuration-to-dateTime" return-type="xs:dateTime">
            <fos:arg name="arg1" type="xs:dateTime"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="xs:dateTime xs:dayTimeDuration numeric"
            >Defines the semantics
         of the <code>+</code> operator when applied to an <code>xs:dateTime</code> and an
            <code>xs:dayTimeDuration</code> value. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:dateTime</code> that is a given duration after a specified
               <code>xs:dateTime</code> (or before, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of adding <code>$arg2</code> to the value of
               <code>$arg1</code> using the algorithm described in Appendix E of <bibref
               ref="xmlschema-2"
               />, disregarding the rule about leap seconds. If <code>$arg2</code>
            is negative, then the result <code>xs:dateTime</code> precedes <code>$arg1</code>.</p>
         <p>The result has the same timezone as <code>$arg1</code>. If <code>$arg1</code> has no
            timezone, the result has no timezone. </p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-dayTimeDuration-to-dateTime(
  xs:dateTime("2000-10-30T11:12:00"),
  xs:dayTimeDuration("P3DT1H15M")
)</eg></fos:expression>
               <fos:result>xs:dateTime("2000-11-02T12:27:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-yearMonthDuration-from-dateTime" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-yearMonthDuration-from-dateTime" return-type="xs:dateTime">
            <fos:arg name="arg1" type="xs:dateTime"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:dateTime xs:yearMonthDuration numeric"
            >Defines the
         semantics of the <code>-</code> operator when applied to an <code>xs:dateTime</code> and an
            <code>xs:yearMonthDuration</code> value. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:dateTime</code> that is a given duration before a specified
               <code>xs:dateTime</code> (or after, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the <code>xs:dateTime</code> computed by negating
               <code>$arg2</code> and adding the result to <code>$arg1</code> using the
            function <code>op:add-yearMonthDuration-to-dateTime</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-yearMonthDuration-from-dateTime(
  xs:dateTime("2000-10-30T11:12:00"),
  xs:yearMonthDuration("P1Y2M")
)</eg></fos:expression>
               <fos:result>xs:dateTime("1999-08-30T11:12:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-dayTimeDuration-from-dateTime" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-dayTimeDuration-from-dateTime" return-type="xs:dateTime">
            <fos:arg name="arg1" type="xs:dateTime"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:dateTime xs:dayTimeDuration numeric"
            >Defines the semantics
         of the <code>-</code> operator when applied to an <code>xs:dateTime</code> an and
            <code>xs:dayTimeDuration</code> values</fos:opermap>
      <fos:summary>
         <p>Returns the <code>xs:dateTime</code> that is a given duration before a specified
               <code>xs:dateTime</code> (or after, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the <code>xs:dateTime</code> computed by negating
               <code>$arg2</code> and adding the result to <code>$arg1</code> using the
            function <code>op:add-dayTimeDuration-to-dateTime</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-dayTimeDuration-from-dateTime(
  xs:dateTime("2000-10-30T11:12:00"),
  xs:dayTimeDuration("P3DT1H15M")
)</eg></fos:expression>
               <fos:result>xs:dateTime("2000-10-27T09:57:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="add-yearMonthDuration-to-date" prefix="op">
      <fos:signatures>
         <fos:proto name="add-yearMonthDuration-to-date" return-type="xs:date">
            <fos:arg name="arg1" type="xs:date"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="xs:date xs:yearMonthDuration numeric"
            >Defines the semantics
         of the <code>+</code> operator when applied to an <code>xs:date</code> and an
            <code>xs:yearMonthDuration</code> value. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:date</code> that is a given duration after a specified
               <code>xs:date</code> (or before, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of casting <code>$arg1</code> to an
               <code>xs:dateTime</code>, adding <code>$arg2</code> using the function
               <code>op:add-yearMonthDuration-to-dateTime</code>, and casting the result back to an
               <code>xs:date</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-yearMonthDuration-to-date(
  xs:date("2000-10-30"),
  xs:yearMonthDuration("P1Y2M")
)</eg></fos:expression>
               <fos:result>xs:date("2001-12-30")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="add-dayTimeDuration-to-date" prefix="op">
      <fos:signatures>
         <fos:proto name="add-dayTimeDuration-to-date" return-type="xs:date">
            <fos:arg name="arg1" type="xs:date"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="xs:date xs:dayTimeDuration numeric"
            >Defines the semantics of
         the <code>+</code> operator when applied to an <code>xs:date</code> and an
            <code>xs:dayTimeDuration</code> value. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:date</code> that is a given duration after a specified
               <code>xs:date</code> (or before, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of casting <code>$arg1</code> to an
               <code>xs:dateTime</code>, adding <code>$arg2</code> using the function
               <code>op:add-dayTimeDuration-to-dateTime</code>, and casting the result back to an
               <code>xs:date</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-dayTimeDuration-to-date(
  xs:date("2004-10-30Z"),
  xs:dayTimeDuration("P2DT2H30M0S")
)</eg></fos:expression>
               <fos:result>xs:date("2004-11-01Z")</fos:result>
               <fos:postamble> The starting instant of the first argument is the
                  <code>xs:dateTime</code> value <code>{ 2004, 10, 30, 0, 0, 0, xs:dayTimeDuration("PT0S") }</code>.
                  Adding the second argument to this gives the <code>xs:dateTime</code> value
                  <code>{ 2004, 11, 1, 2, 30, 0, xs:dayTimeDuration("PT0S") }</code>. The time components are then
                  discarded. </fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-yearMonthDuration-from-date" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-yearMonthDuration-from-date" return-type="xs:date">
            <fos:arg name="arg1" type="xs:date"/>
            <fos:arg name="arg2" type="xs:yearMonthDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:date xs:yearMonthDuration numeric"
            >Defines the semantics
         of the <code>-</code> operator when applied to an <code>xs:date</code> and an
            <code>xs:yearMonthDuration</code> value. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:date</code> that is a given duration before a specified
               <code>xs:date</code> (or after, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>Returns the <code>xs:date</code> computed by negating <code>$arg2</code> and adding the
            result to <code>$arg1</code> using the function
               <code>op:add-yearMonthDuration-to-date</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-yearMonthDuration-from-date(
  xs:date("2000-10-30"),
  xs:yearMonthDuration("P1Y2M")
)</eg></fos:expression>
               <fos:result>xs:date("1999-08-30")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-yearMonthDuration-from-date(
  xs:date("2000-02-29Z"),
  xs:yearMonthDuration("P1Y")
)</eg></fos:expression>
               <fos:result>xs:date("1999-02-28Z")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-yearMonthDuration-from-date(
  xs:date("2000-10-31-05:00"),
  xs:yearMonthDuration("P1Y1M")
)</eg></fos:expression>
               <fos:result>xs:date("1999-09-30-05:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-dayTimeDuration-from-date" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-dayTimeDuration-from-date" return-type="xs:date">
            <fos:arg name="arg1" type="xs:date"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:date xs:dayTimeDuration numeric"
            >Defines the semantics of
         the <code>-</code> operator when applied to an <code>xs:date</code> and an
            <code>xs:dayTimeDuration</code>. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:date</code> that is a given duration before a specified
               <code>xs:date</code> (or after, if the duration is negative).</p>
      </fos:summary>
      <fos:rules>
         <p>Returns the <code>xs:date</code> computed by negating <code>$arg2</code> and adding the
            result to <code>$arg1</code> using the function
               <code>op:add-dayTimeDuration-to-date</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-dayTimeDuration-from-date(
  xs:date("2000-10-30"),
  xs:dayTimeDuration("P3DT1H15M")
)</eg></fos:expression>
               <fos:result>xs:date("2000-10-26")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="add-dayTimeDuration-to-time" prefix="op">
      <fos:signatures>
         <fos:proto name="add-dayTimeDuration-to-time" return-type="xs:time">
            <fos:arg name="arg1" type="xs:time"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="+" types="xs:time xs:dayTimeDuration numeric"
            >Defines the semantics of
         the <code>+</code> operator when applied to an <code>xs:time</code> and an
            <code>xs:dayTimeDuration</code> value.</fos:opermap>
      <fos:summary>
         <p>Returns the <code>xs:time</code> value that is a given duration after a specified
               <code>xs:time</code> (or before, if the duration is negative or causes wrap-around
            past midnight)</p>
      </fos:summary>
      <fos:rules>
         <p>First, the days component in the canonical lexical representation of <code>$arg2</code>
            is set to zero (0) and the value of the resulting <code>xs:dayTimeDuration</code> is
            calculated. Alternatively, the value of <code>$arg2</code> modulus 86,400 is used as the
            second argument. This value is added to the value of <code>$arg1</code> converted to an
               <code>xs:dateTime</code> using a reference date such as <code>1972-12-31</code>, and
            the time component of the result is returned. Note that the <code>xs:time</code>
            returned may occur in a following or preceding day and may be less than
               <code>$arg1</code>.</p>
         <p>The result has the same timezone as <code>$arg1</code>. If <code>$arg1</code> has no
            timezone, the result has no timezone.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-dayTimeDuration-to-time(
  xs:time("11:12:00"),
  xs:dayTimeDuration("P3DT1H15M")
)</eg></fos:expression>
               <fos:result>xs:time("12:27:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:add-dayTimeDuration-to-time(
  xs:time("23:12:00+03:00"),
  xs:dayTimeDuration("P1DT3H15M")
)</eg></fos:expression>
               <fos:result>xs:time("02:27:00+03:00")</fos:result>
               <fos:postamble>That is, <code>{ 0, 0, 0, 2, 27, 0, xs:dayTimeDuration("PT3H") }</code></fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="subtract-dayTimeDuration-from-time" prefix="op">
      <fos:signatures>
         <fos:proto name="subtract-dayTimeDuration-from-time" return-type="xs:time">
            <fos:arg name="arg1" type="xs:time"/>
            <fos:arg name="arg2" type="xs:dayTimeDuration"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="-" types="xs:time xs:dayTimeDuration numeric"
            >Defines the semantics of
         the <code>-</code> operator when applied to an <code>xs:time</code> and an
            <code>xs:dayTimeDuration</code> value. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>xs:time</code> value that is a given duration before a specified
               <code>xs:time</code> (or after, if the duration is negative or causes wrap-around
            past midnight)</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the result of negating <code>$arg2</code> and adding the result to
               <code>$arg1</code> using the function <code>op:add-dayTimeDuration-to-time</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-dayTimeDuration-from-time(
  xs:time("11:12:00"),
  xs:dayTimeDuration("P3DT1H15M")
)</eg></fos:expression>
               <fos:result>xs:time("09:57:00")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>op:subtract-dayTimeDuration-from-time(
  xs:time("08:20:00-05:00"),
  xs:dayTimeDuration("P23DT10H10M")
)</eg></fos:expression>
               <fos:result>xs:time("22:10:00-05:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="format-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="format-dateTime" return-type="xs:string?">
            <fos:arg name="value" type="xs:dateTime?"/>
            <fos:arg name="picture" type="xs:string"/>
            <fos:arg name="language" type="xs:string?" default="()"/>
            <fos:arg name="calendar" type="xs:string?" default="()"/>
            <fos:arg name="place" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="default-calendar default-language default-place implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string containing an <code>xs:dateTime</code> value formatted for display.</p>
      </fos:summary>
      <fos:rules>
         <p>See <specref ref="rules-for-datetime-formatting"/>.</p>
      </fos:rules>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The 3rd, 4th, and 5th arguments are now optional; previously the function required either 2 or 5 arguments.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="format-date" prefix="fn">
      <fos:signatures>
         <fos:proto name="format-date" return-type="xs:string?">
            <fos:arg name="value" type="xs:date?"/>
            <fos:arg name="picture" type="xs:string"/>
            <fos:arg name="language" type="xs:string?" default="()"/>
            <fos:arg name="calendar" type="xs:string?" default="()"/>
            <fos:arg name="place" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="default-calendar default-language default-place implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string containing an <code>xs:date</code> value formatted for display.</p>
      </fos:summary>
      <fos:rules>
         <p>See <specref ref="rules-for-datetime-formatting"/>.</p>
      </fos:rules>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The 3rd, 4th, and 5th arguments are now optional; previously the function required either 2 or 5 arguments.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="format-time" prefix="fn">
      <fos:signatures>
         <fos:proto name="format-time" return-type="xs:string?">
            <fos:arg name="value" type="xs:time?"/>
            <fos:arg name="picture" type="xs:string"/>
            <fos:arg name="language" type="xs:string?" default="()"/>
            <fos:arg name="calendar" type="xs:string?" default="()"/>
            <fos:arg name="place" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="default-calendar default-language default-place implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string containing an <code>xs:time</code> value formatted for display.</p>
      </fos:summary>
      <fos:rules>
         <p>See <specref ref="rules-for-datetime-formatting"/>.</p>
      </fos:rules>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The 3rd, 4th, and 5th arguments are now optional; previously the function required either 2 or 5 arguments.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="parse-ietf-date" prefix="fn">
      <fos:signatures>
         <fos:proto name="parse-ietf-date" return-type="xs:dateTime?">
            <fos:arg name="value" type="xs:string?" example="'Wed, 06 Jun 1994 07:29:35 GMT'"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>

      <fos:summary>
         <p>Parses a string containing the date and time in IETF format, returning the corresponding
               <code>xs:dateTime</code> value.</p>
      </fos:summary>
      <fos:rules>
         <p>The function accepts a string matching the production <code>input</code> in the
            following grammar:</p>
         <table role="scrap">
           <tbody>
            <tr>
               <td>
                  <code>input</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>S? (dayname ","? S)? ((datespec S time) | asctime) S?</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>dayname</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>"Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun" | "Monday | "Tuesday"
                     | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday"</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>datespec</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>daynum dsep monthname dsep year</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>asctime</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>monthname dsep daynum S time S year</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>dsep</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>S | (S? "-" S?)</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>daynum</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>digit digit?</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>year</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>digit digit (digit digit)?</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>digit</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>[0-9]</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>monthname</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>"Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" |
                     "Oct" | "Nov" | "Dec"</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>time</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>hours ":" minutes (":" seconds)? (S? timezone)?</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>hours</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <phrase><code>digit digit?</code></phrase>
               </td>
            </tr>
            <tr>
               <td>
                  <code>minutes</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>digit digit</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>seconds</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>digit digit ("." digit+)?</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>timezone</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>tzname | tzoffset (S? "(" S? tzname S? ")")?</code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>tzname</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>"UT" | "UTC" | "GMT" | "EST" | "EDT" | "CST" | "CDT" | "MST" | "MDT" | "PST"
                     | "PDT" </code>
               </td>
            </tr>
            <tr>
               <td>
                  <code>tzoffset</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <phrase><code>("+"|"-") hours ":"? minutes?</code></phrase>
               </td>
            </tr>
            <tr>
               <td>
                  <code>S</code>
               </td>
               <td>
                  <code>::=</code>
               </td>
               <td>
                  <code>(x09 | x0A | x0D | x20)+</code>
               </td>
            </tr>
          </tbody>
         </table>

         <p>The input is case-insensitive: upper-case and lower-case distinctions in the above
            grammar show the conventional usage, but otherwise have no significance.</p>
         <p>If the input is the empty sequence, the result is the empty sequence.</p>
         <p>The <code>dayname</code>, if present, is ignored.</p>
         <p>The <code>daynum</code>, <code>monthname</code>, and <code>year</code> supply the day,
            month, and year of the resulting <code>xs:dateTime</code> value. A two-digit year
               <rfc2119>must</rfc2119> have 1900 added to it. A year such as 0070 is to be treated
            as given; negative years are not permitted.</p>
         <p>The <code>hours</code>, <code>minutes</code>, and <code>seconds</code> (including
            fractional seconds) values supply the corresponding components of the resulting
               <code>xs:dateTime</code> value; if the <code>seconds</code> value 
            <phrase>or the fractional seconds value</phrase> is absent then zero
            is assumed.</p>
         <p>If both a <code>tzoffset</code> and a <code>tzname</code> are supplied then the
               <code>tzname</code> is ignored.</p>
         <p>If a <code>tzoffset</code> is supplied then this defines the hours and minutes parts of the timezone offset:</p>
         <ulist>
            <item>
               <p>If it contains a colon, this separates the hours part from the minutes part.</p>
            </item>
            <item>
               <p>Otherwise, the grammar allows a sequence of from one to four digits. These are interpreted
            as <code>H</code>, <code>HH</code>, <code>HMM</code>, or <code>HHMM</code> respectively, where <code>H</code>
            or <code>HH</code> is the hours part, and <code>MM</code> (if present) is the minutes part.</p>
            </item>
            <item><p>If the minutes part is absent it defaults to <code>00</code>.</p></item>
         </ulist>

         <p>If a <code>tzname</code> is supplied with no <code>tzoffset</code> then it is translated
            to a timezone offset as follows:</p>
         <table role="data">
            <thead>
               <tr>
                  <th>tzname</th>
                  <th>Offset</th>
               </tr>
            </thead>
            <tbody>
               <tr>
                  <td>UT, UTC, GMT</td>
                  <td>00:00</td>
               </tr>
               <tr>
                  <td>EST</td>
                  <td>-05:00</td>
               </tr>
               <tr>
                  <td>EDT</td>
                  <td>-04:00</td>
               </tr>
               <tr>
                  <td>CST</td>
                  <td>-06:00</td>
               </tr>
               <tr>
                  <td>CDT</td>
                  <td>-05:00</td>
               </tr>
               <tr>
                  <td>MST</td>
                  <td>-07:00</td>
               </tr>
               <tr>
                  <td>MDT</td>
                  <td>-06:00</td>
               </tr>
               <tr>
                  <td>PST</td>
                  <td>-08:00</td>
               </tr>
               <tr>
                  <td>PDT</td>
                  <td>-07:00</td>
               </tr>
            </tbody>
         </table>
         <p>If neither a <code>tzoffset</code> nor <code>tzname</code> is supplied, a timezone
            offset of <code>00:00</code> is assumed.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref spec="FO" class="RG" code="0010"
            /> if the input does
            not match the grammar, or if the resulting date/time value is invalid
            (for example, <code>"31 February"</code>).</p>
      </fos:errors>
      <fos:notes>
         <p>The <code>parse-ietf-date</code> function attempts to interpret its input as a date
            in any of the three formats specified by HTTP <bibref
               ref="rfc2616"/>.</p>

         <p>These formats are used widely on the Internet to represent timestamps, and were
            specified in:</p>
         <ulist>
            <item><p><bibref ref="rfc822"/> (electronic mail), extended in <bibref ref="rfc1123"
               /> to allow four-digit years;</p></item>
            <item><p><bibref ref="rfc850"/> (Usenet Messages), obsoleted by <bibref ref="rfc1036"
               />;</p></item>
            <item><p>POSIX <code>asctime()</code> format</p></item>
         </ulist>
         <p><bibref ref="rfc2616"
            /> (HTTP) officially uses a subset of those three formats restricted to GMT.</p>

         <p>The grammar for this function is slightly more liberal than the RFCs (reflecting the internet tradition of being liberal in what is accepted).
            For example the function:</p>

         <olist>
            <item>
               <p>Accepts a single-digit value where appropriate in place of a two-digit value with a leading zero (so
                  <code>"Wed 1 Jun"</code> is acceptable in place of <code>"Wed 01 Jun"</code>,
                  <phrase>and the timezone offset <code>"-5:00"</code> is equivalent to <code>"-05:00"</code>)</phrase></p>
            </item>
            <item>
               <p>Accepts one or more whitespace characters (x20, x09, x0A, x0D) wherever a single
                  space is required, and allows whitespace to be omitted where it is not required
                  for parsing</p>
            </item>
            <item>
               <p>Accepts and ignores whitespace characters (x20, x09, x0A, x0D) at the start or end
                  of the string.</p>
            </item>
         </olist>

         <p>In new protocols IETF recommends the format of <bibref ref="rfc3339"
               />, which is based on a profile of
            ISO 8601 similar to that already used in XPath and XSD, but the “approximate” <bibref
               ref="rfc822"/>
            format described here is very widely used.</p>

         <p>An <bibref ref="rfc1123"
               /> date can be generated approximately using <function>fn:format-dateTime</function> with a picture
            string of <code>"[FNn3], [D01] [MNn3] [Y04] [H01]:[m01]:[s01] [Z0000]"</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>parse-ietf-date("Wed, 06 Jun 1994 07:29:35 GMT")</fos:expression>
               <fos:result>xs:dateTime("1994-06-06T07:29:35Z")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-ietf-date("Wed, 6 Jun 94 07:29:35 GMT")</fos:expression>
               <fos:result>xs:dateTime("1994-06-06T07:29:35Z")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-ietf-date("Wed Jun 06 11:54:45 EST 2013")</fos:expression>
               <fos:result>xs:dateTime("2013-06-06T11:54:45-05:00")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-ietf-date("Sunday, 06-Nov-94 08:49:37 GMT")</fos:expression>
               <fos:result>xs:dateTime("1994-11-06T08:49:37Z")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-ietf-date("Wed, 6 Jun 94 07:29:35 +0500")</fos:expression>
               <fos:result>xs:dateTime("1994-06-06T07:29:35+05:00")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>

   </fos:function>

   <fos:function name="resolve-QName" prefix="fn">
      <fos:signatures>
         <fos:proto name="resolve-QName" return-type="xs:QName?">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="element" type="element()" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an <code>xs:QName</code> value (that is, an expanded-QName) by taking an
               <code>xs:string</code> that has the lexical form of an <code>xs:QName</code> (a
            string in the form <code>"prefix:local-name"</code> or <code>"local-name"</code>)
            and resolving it using the in-scope namespaces for a given element.</p>
      </fos:summary>
      <fos:rules>

         <p>If <code>$value</code> is the empty sequence, returns the empty sequence.</p>
         <p>More specifically, the function searches the namespace bindings of <code>$element</code>
            for a binding whose name matches the prefix of <code>$value</code>, or the zero-length
            string if it has no prefix, and returns an expanded-QName whose local name is taken
            from the supplied <code>$value</code>, and whose namespace URI is taken from the string
            value of the namespace binding.</p>

         <p>If the <code>$value</code> has no prefix, and there is no namespace binding for
               <code>$element</code> corresponding to the default (unnamed) namespace, then the
            resulting expanded-QName has no namespace part.</p>
         <p>The prefix (or absence of a prefix) in the supplied <code>$value</code> argument is
            retained in the returned expanded-QName, as described in <xspecref
               spec="DM40" ref="terminology"/>.</p>

      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="CA" code="0002"
               /> if <code>$value</code> does
            not have the correct lexical form for an instance of <code>xs:QName</code>.</p>
         <p>A dynamic error is raised <errorref class="NS" code="0004"
               /> if <code>$value</code> has
            a prefix and there is no namespace binding for <code>$element</code> that matches this
            prefix.</p>
      </fos:errors>
      <fos:notes>
         <p>Sometimes the requirement is to construct an <code>xs:QName</code> without using the
            default namespace. This can be achieved by writing:</p>
         <eg xml:space="preserve">if (contains($value, ":"))
then resolve-QName($value, $element)
else QName("", $value)</eg>
         <p>If the requirement is to construct an <code>xs:QName</code> using the namespaces in the
            static context, then the <code>xs:QName</code> constructor should be used.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="element" id="v-resolve-qname-element"><![CDATA[<e xmlns:eg="http://ns.example.com/"/>]]></fos:variable>

         <fos:example>
            <fos:test use="v-resolve-qname-element">
               <fos:expression>fn:resolve-QName("hello", $element)</fos:expression>
               <fos:result>#Q{}hello</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-resolve-qname-element">
               <fos:expression>fn:resolve-QName("eg:myFunc", $element)</fos:expression>
               <fos:result>#Q{http://ns.example.com/}eg:myFunc</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="QName" prefix="fn">
      <fos:signatures>
         <fos:proto name="QName" return-type="xs:QName">
            <fos:arg name="uri" type="xs:string?"/>
            <fos:arg name="qname" type="xs:string"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an <code>xs:QName</code> value formed using a supplied namespace URI and lexical QName.</p>
      </fos:summary>
      <fos:rules>

         <p>The namespace URI in the returned QName is taken from <code>$uri</code>. If
               <code>$uri</code> is the zero-length string or the empty sequence, it represents
            “no namespace”.</p>
         <p>The prefix (or absence of a prefix) in <code>$qname</code> is retained in the
            returned <code>xs:QName</code> value.</p>
         <p>The local name in the result is taken from the local part of
            <code>$qname</code>.</p>

      </fos:rules>
      <fos:errors>
 
           <p>A dynamic error is raised <errorref class="CA" code="0002"
               /> if <code>$qname</code>
            does not have the correct lexical form for an instance of <code>xs:QName</code>.</p>
           <p>A dynamic error is raised <errorref class="CA" code="0002"
               /> if <code>$uri</code>
            is the zero-length string or the empty sequence, and the value of
               <code>$qname</code> contains a colon (<code>:</code>).</p>
           <p>A dynamic error <rfc2119>may</rfc2119> be raised <errorref class="CA" code="0002"
               /> if
               <code>$uri</code> is not a valid URI (XML Namespaces 1.0) or IRI (XML Namespaces
            1.1). </p>

      </fos:errors>

      <fos:examples>
 
         <fos:example>
            <fos:test>
               <fos:expression>QName("http://www.example.com/example", "person")</fos:expression>
               <fos:result>#Q{http://www.example.com/example}person</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>QName("http://www.example.com/example", "ht:person")</fos:expression>
               <fos:result>#Q{http://www.example.com/example}ht:person</fos:result>
            </fos:test>
            
         </fos:example>

      </fos:examples>

   </fos:function>
   <fos:function name="parse-QName" prefix="fn" diff="add" at="B">
      <fos:signatures>
         <fos:proto name="parse-QName" return-type="xs:QName?">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="namespaces">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an <code>xs:QName</code> value formed by parsing an EQName.</p>
      </fos:summary>
      <fos:rules>
            <p>If <code>$value</code> is the empty sequence, the result is the empty sequence.</p>

            <p>Otherwise, leading and trailing whitespace in <code>$value</code> is stripped:
            call the result <var>V</var></p>
            <p>If <var>V</var> is castable to <code>xs:NCName</code>,
               the result is <code>fn:QName("", $value)</code>: that is, a QName in no namespace.</p>
            <p>If <var>V</var> is in the lexical space of <code>xs:QName</code>
               (that is, if it is in the form <code>prefix:local</code>), the result is <code>xs:QName($value)</code>.
               Note that this result depends on the in-scope prefixes in the static context, and may result in
               various error conditions.</p>
            <p>If <var>V</var> takes the form of a
               XPath <xnt spec="XP40" ref="URIQualifiedName">URIQualifiedName</xnt>
               (that is, <code>Q{uri}local</code>, where the <code>uri</code> part may be zero-length,
               or <code>Q{uri}prefix:local</code>),
               then the result is <code>fn:QName(uri, local)</code> or <code>fn:QName(uri, prefix:local)</code>
               respectively.</p>
            <p>The rules used for parsing a <xnt spec="XP40" ref="BracedURILiteral"/> within a 
            <xnt spec="XP40" ref="URIQualifiedName">URIQualifiedName</xnt> are the XPath rules,
                  not the XQuery rules (the XQuery rules require special characters such as <code>&lt;</code>
                  and <code>&amp;</code> to be escaped).</p>
         
      </fos:rules>
      <fos:errors>

            <p>A dynamic error is raised <errorref class="CA" code="0002"/>
               if the supplied value of <code>$value</code>, after whitespace normalization,
               does not match the XPath production <xspecref spec="XP40" ref="EQName">EQName</xspecref>,
               or if the input is a <code>URIQualifiedName</code> in which the namespace prefix
               is present but the namespace URI is absent.</p>
            <p>A dynamic error is raised <errorref class="NS" code="0004"/> if
               the supplied value of <code>$value</code>, after whitespace normalization,
               is in the form <code>prefix:local</code> (with a non-absent prefix), and
               the prefix cannot be resolved to a namespace URI using the in-scope namespace
               bindings from the static context.</p>
      </fos:errors>
      
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression>fn:parse-QName("Q{http://www.example.com/ns}person")</fos:expression>
               <fos:result>fn:QName("http://www.example.com/ns", "person")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>fn:parse-QName("person")</fos:expression>
               <fos:result>fn:QName("", "person")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>fn:parse-QName("Q{}person")</fos:expression>
               <fos:result>fn:QName("", "person")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>fn:parse-QName("Q{http://www.example.com/ns}xmp:person")</fos:expression>
               <fos:result>fn:QName("http://www.example.com/ns", "xmp:person")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>declare namespace xmp = "http://www.example.com/ns";
fn:parse-QName("xmp:person")</eg></fos:expression>
               <fos:result>#Q{http://www.example.com/ns}xmp:person</fos:result>
            </fos:test>
         </fos:example>


      </fos:examples>
      <fos:changes>
         <fos:change issue="1" PR="207" date="2022-11-15"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="expanded-QName" prefix="fn" diff="add" at="B">
      <fos:signatures>
         <fos:proto name="expanded-QName" return-type="xs:string?">
            <fos:arg name="value" type="xs:QName?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string representation of an <code>xs:QName</code> in the format <code>Q{uri}local</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, returns the empty sequence.</p>
         <p>The result is a string in the format <code>Q{uri}local</code>, where:</p>
         <ulist>
            <item><p><code>uri</code> 
               is the result of <code>fn:string(fn:namespace-uri-from-QName($value))</code>
               (which will be a zero-length string if the QName is in no namespace), and </p></item>
            <item><p><code>local</code> is the result of 
               <code>fn:local-name-from-QName($value)</code>.</p></item>
         </ulist>
         <p>There is no escaping of special characters in the namespace URI. If the namespace URI
            contains curly braces, the resulting string will not be a valid 
            <xnt spec="XP40" ref="BracedURILiteral">BracedURILiteral</xnt>.</p>
      </fos:rules>
 
      
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>QName("http://example.com/", "person")
=> expanded-QName()</eg></fos:expression>
               <fos:result>"Q{http://example.com/}person"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>QName("", "person")
=> expanded-QName()</eg></fos:expression>
               <fos:result>"Q{}person"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1" PR="207" date="2022-11-15"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <!--<fos:function name="QName-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="QName-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:QName"/>
            <fos:arg name="arg2" type="xs:QName"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:QName numeric" other-operators="ne"
            >Defines the semantics
         of the <code>eq</code> and <code>ne</code> operators when applied to two values of type <code>xs:QName</code>. </fos:opermap>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if two supplied QNames have the same namespace URI and the
            same local part.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>true</code> if the namespace URIs of <code>$arg1</code> and
               <code>$arg2</code> are equal and the local names of <code>$arg1</code> and
               <code>$arg2</code> are equal.</p>
         <p>Otherwise, the function returns <code>false</code>.</p>
         <p>The namespace URI parts are considered equal if they are both <xtermref ref="dt-absent"
               spec="DM40"
               >absent</xtermref>, or if they are both present and equal under the rules
            of the <function>fn:codepoint-equal</function> function.</p>
         <p>The local parts are also compared under the rules of the <function>fn:codepoint-equal</function>
            function.</p>
      </fos:rules>
      <fos:notes>
         <p>The prefix parts of <code>$arg1</code> and <code>$arg2</code>, if any, are ignored.</p>
      </fos:notes>
   </fos:function>-->
   <fos:function name="prefix-from-QName" prefix="fn">
      <fos:signatures>
         <fos:proto name="prefix-from-QName" return-type="xs:NCName?">
            <fos:arg name="value" type="xs:QName?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the prefix component of the supplied QName.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>If <code>$value</code> has no prefix component the function returns the empty
            sequence.</p>
         <p>Otherwise, the function returns an <code>xs:NCName</code> representing the prefix
            component of <code>$value</code>.</p>
      </fos:rules>
   </fos:function>
   <fos:function name="local-name-from-QName" prefix="fn">
      <fos:signatures>
         <fos:proto name="local-name-from-QName" return-type="xs:NCName?">
            <fos:arg name="value" type="xs:QName?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the local part of the supplied QName.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:NCName</code> representing the local part of
            <code>$value</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>local-name-from-QName(#Q{http://www.example.com/ns}person)</eg></fos:expression>
               <fos:result>"person"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="namespace-uri-from-QName" prefix="fn">
      <fos:signatures>
         <fos:proto name="namespace-uri-from-QName" return-type="xs:anyURI?">
            <fos:arg name="value" type="xs:QName?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the namespace URI part of the supplied QName.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns an <code>xs:anyURI</code> representing the namespace URI
            part of <code>$value</code>.</p>
         <p>If <code>$value</code> is in no namespace, the function returns the zero-length
               <code>xs:anyURI</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>namespace-uri-from-QName(#Q{http://www.example.com/ns}person)</eg></fos:expression>
               <fos:result>xs:anyURI("http://www.example.com/ns")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="namespace-uri-for-prefix" prefix="fn">
      <fos:signatures>
         <fos:proto name="namespace-uri-for-prefix" return-type="xs:anyURI?">
            <fos:arg name="value" type="(xs:NCName | enum(''))?"/>
            <fos:arg name="element" type="element()" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the namespace URI of one of the in-scope namespaces for <code>$element</code>,
            identified by its namespace prefix.</p>
      </fos:summary>
      <fos:rules>
         <p diff="chg" at="A"
               >The function returns the result of the expression <code>map:get(fn:in-scope-namespaces($element), string($value))</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:variable name="e" id="v-namespace-uri-for-prefix-e"><![CDATA[
<z:a xmlns="http://example.org/one" xmlns:z="http://example.org/two">
  <b xmlns=""/>
</z:a>]]></fos:variable>
         <fos:example>
            <fos:test use="v-namespace-uri-for-prefix-e" spec="XQuery">
               <fos:expression>namespace-uri-for-prefix("z", $e)</fos:expression>
               <fos:result>"http://example.org/two"</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-for-prefix-e" spec="XQuery">
               <fos:expression>namespace-uri-for-prefix("", $e)</fos:expression>
               <fos:result>"http://example.org/one"</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-for-prefix-e" spec="XQuery">
               <fos:expression>namespace-uri-for-prefix((), $e)</fos:expression>
               <fos:result>"http://example.org/one"</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-for-prefix-e" spec="XQuery">
               <fos:expression>namespace-uri-for-prefix("xml", $e)</fos:expression>
               <fos:result>"http://www.w3.org/XML/1998/namespace"</fos:result>
            </fos:test>

         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="in-scope-namespaces" prefix="fn" diff="add" at="A">
      <fos:signatures>
         <fos:proto name="in-scope-namespaces"
            return-type="map((xs:NCName | enum('')), xs:anyURI)">
            <fos:arg name="element" type="element()" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the in-scope namespaces of an element node, as a map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a map representing the prefixes of the in-scope
            namespaces for <code>$element</code>. The map contains one entry
         for each in-scope namespace: the key of the entry is the namespace
         prefix or a zero-length string, and the corresponding value is the namespace URI.</p>

         <p>For namespace bindings that have a prefix, the key represents the prefix as an
            instance of <code>xs:NCName</code>. For the default namespace, which has no prefix, the key is
            the zero-length string as an instance of <code>xs:string</code>.</p>

         <p>The order of entries in the returned map is <termref def="implementation-dependent"/>.</p>

      </fos:rules>
      <fos:notes>
         <p>The XML namespace is in scope for every element, so the result will always include an entry
            with key <code>"xml"</code> and corresponding value <code>http://www.w3.org/XML/1998/namespace</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="e" id="v-in-scope-namespaces-e"><![CDATA[
<z:a xmlns="http://example.org/one" xmlns:z="http://example.org/two">
  <b xmlns=""/>
</z:a>]]></fos:variable>
         <fos:example>
            <fos:test use="v-in-scope-namespaces-e" spec="XQuery">
               <fos:expression>in-scope-namespaces($e)</fos:expression>
               <fos:result><eg>{
  "": "http://example.org/one",
  "z": "http://example.org/two",
  "xml": "http://www.w3.org/XML/1998/namespace"
}</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="in-scope-prefixes" prefix="fn">
      <fos:signatures>
         <fos:proto name="in-scope-prefixes" return-type="xs:string*">
            <fos:arg name="element" type="element()" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic-wrt-ordering</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the prefixes of the in-scope namespaces for an element node.</p>
      </fos:summary>
      <fos:rules>
         <p diff="chg" at="A"
               >The function returns the result of the expression
            <code>map:keys(fn:in-scope-namespaces($element))</code> (but in no defined order).</p>

      </fos:rules>
      <fos:notes>
         <p>The XML namespace is in scope for every element, so the result will always include the string <code>"xml"</code>.</p>
      </fos:notes>
   </fos:function>
   

   <!--<fos:function name="NOTATION-equal" prefix="op">
      <fos:signatures>
         <fos:proto name="NOTATION-equal" return-type="xs:boolean">
            <fos:arg name="arg1" type="xs:NOTATION"/>
            <fos:arg name="arg2" type="xs:NOTATION"/>
         </fos:proto>
      </fos:signatures>
      <fos:opermap operator="eq" types="xs:NOTATION numeric" other-operators="ne"
            >Defines the
         semantics of the <code>eq</code> and <code>ne</code> operators when applied to two values of type
            <code>xs:NOTATION</code>. </fos:opermap>
      <fos:summary>
         <p>Returns <code>true</code> if the two <code>xs:NOTATION</code> values have the same
            namespace URI and the same local part.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>true</code> if the namespace URIs of <code>$arg1</code> and
               <code>$arg2</code> are equal and the local names of <code>$arg1</code> and
               <code>$arg2</code> are equal.</p>
         <p>Otherwise, the function returns <code>false</code>.</p>
         <p>The namespace URI parts are considered equal if they are both <xtermref ref="dt-absent"
               spec="DM40"
               >absent</xtermref>, or if they are both present and equal under the rules
            of the <function>fn:codepoint-equal</function> function.</p>
         <p>The local parts are also compared under the rules of the <function>fn:codepoint-equal</function>
            function.</p>
      </fos:rules>
      <fos:notes>
         <p>The prefix parts of <code>$arg1</code> and <code>$arg2</code>, if any, are ignored.</p>
      </fos:notes>
   </fos:function>-->
   <fos:function name="name" prefix="fn">
      <fos:signatures>
         <fos:proto name="name" return-type="xs:string">
            <fos:arg name="node" type="node()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the name of a node, as an <code>xs:string</code> that is either the zero-length
            string, or has the lexical form of an <code>xs:QName</code>. </p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the function returns the zero-length string.</p>
         <p>If the node identified by <code>$node</code> has no name (that is, if it is a document
            node, a comment, a text node, or a namespace node having no name), the function returns
            the zero-length string.</p>
         <p>Otherwise, the function returns the value of the expression
               <code>fn:string(fn:node-name($node))</code>.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>Because the result depends on the choice of namespace prefixes in the source document,
         it is not good practice to use the result of this function for anything other than display
         purposes. For example, the test <code>name(.) = 'my:profile'</code> will fail if the source
         document uses an unexpected namespace prefix. Such a test (assuming it relates to an element node) 
         is better written as <code>boolean(self::my:profile)</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="e" id="v-name-e"><![CDATA[<doc>
  <p id="alpha" xml:id="beta">One</p>
  <p id="gamma" xmlns="http://example.com/ns">Two</p>
  <ex:p id="delta" xmlns:ex="http://example.com/ns">Three</ex:p>
  <?pi 3.14159?>
</doc>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-name-e" spec="XQuery">
               <fos:expression>name($e//*[@id = 'alpha'])</fos:expression>
               <fos:result>"p"</fos:result>
            </fos:test>
            <fos:test use="v-name-e" spec="XQuery">
               <fos:expression>name($e//*[@id = 'gamma'])</fos:expression>
               <fos:result>"p"</fos:result>
            </fos:test>
            <fos:test use="v-name-e" spec="XQuery">
               <fos:expression>name($e//*[@id = 'delta'])</fos:expression>
               <fos:result>"ex:p"</fos:result>
            </fos:test>
            <fos:test use="v-name-e" spec="XQuery">
               <fos:expression>name($e//processing-instruction())</fos:expression>
               <fos:result>"pi"</fos:result>
            </fos:test>
            <fos:test use="v-name-e" spec="XQuery">
               <fos:expression>name($e//*[@id = 'alpha']/text())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
            <fos:test use="v-name-e" spec="XQuery">
               <fos:expression>name($e//*[@id = 'alpha']/@id)</fos:expression>
               <fos:result>"id"</fos:result>
            </fos:test>
            <fos:test use="v-name-e" spec="XQuery">
               <fos:expression>name($e//*[@id = 'alpha']/@xml:id)</fos:expression>
               <fos:result>"xml:id"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="local-name" prefix="fn">
      <fos:signatures>
         <fos:proto name="local-name" return-type="xs:string">
            <fos:arg name="node" type="node()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the local part of the name of <code>$node</code> as an <code>xs:string</code>
            that is either the zero-length string, or has the lexical form of an
               <code>xs:NCName</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the function returns the zero-length string.</p>
         <p>If the node identified by <code>$node</code> has no name (that is, if it is a document
            node, a comment, a text node, or a namespace node having no name), the function returns
            the zero-length string.</p>
         <p>Otherwise, the function returns the local part of the expanded-QName of the node
            identified by <code>$node</code>, as determined by the <code>dm:node-name</code> accessor
            defined in <xspecref
               spec="DM40" ref="dm-node-name"
               />. This will be an
               <code>xs:string</code> whose lexical form is an <code>xs:NCName</code>.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not a single node, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:examples>
         <fos:variable name="e" id="v-local-name-e"><![CDATA[<doc>
  <p id="alpha" xml:id="beta">One</p>
  <p id="gamma" xmlns="http://example.com/ns">Two</p>
  <ex:p id="delta" xmlns:ex="http://example.com/ns">Three</ex:p>
  <?pi 3.14159?>
</doc>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-local-name-e" spec="XQuery">
               <fos:expression>local-name($e//*[@id = 'alpha'])</fos:expression>
               <fos:result>"p"</fos:result>
            </fos:test>
            <fos:test use="v-local-name-e" spec="XQuery">
               <fos:expression>local-name($e//*[@id = 'gamma'])</fos:expression>
               <fos:result>"p"</fos:result>
            </fos:test>
            <fos:test use="v-local-name-e" spec="XQuery">
               <fos:expression>local-name($e//*[@id = 'delta'])</fos:expression>
               <fos:result>"p"</fos:result>
            </fos:test>
            <fos:test use="v-local-name-e" spec="XQuery">
               <fos:expression>local-name($e//processing-instruction())</fos:expression>
               <fos:result>"pi"</fos:result>
            </fos:test>
            <fos:test use="v-local-name-e" spec="XQuery">
               <fos:expression>local-name($e//*[@id = 'alpha']/text())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
            <fos:test use="v-local-name-e" spec="XQuery">
               <fos:expression>local-name($e//*[@id = 'alpha']/@id)</fos:expression>
               <fos:result>"id"</fos:result>
            </fos:test>
            <fos:test use="v-local-name-e" spec="XQuery">
               <fos:expression>local-name($e//*[@id = 'alpha']/@xml:id)</fos:expression>
               <fos:result>"id"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="namespace-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="namespace-uri" return-type="xs:anyURI">
            <fos:arg name="node" type="node()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the namespace URI part of the name of <code>$node</code>, as an
               <code>xs:anyURI</code> value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, if the node identified by is neither an
            element nor an attribute node, or if it is an element or attribute node whose
            expanded-QName (as determined by the <code>dm:node-name</code> accessor in the
            <xspecref spec="DM40" ref="dm-node-name"/>) is in no namespace,
            then the function returns the zero-length <code>xs:anyURI</code> value.</p>
         <p>Otherwise, the result will be the namespace URI part of the expanded-QName of the node
            identified by <code>$node</code>, as determined by the <code>dm:node-name</code> accessor
            defined in <xspecref
               spec="DM40" ref="dm-node-name"
               />), returned as an
               <code>xs:anyURI</code> value.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>
      </fos:errors>
      <fos:examples>
         <fos:variable name="e" id="v-namespace-uri-e"><![CDATA[<doc>
  <p id="alpha" xml:id="beta">One</p>
  <p id="gamma" xmlns="http://example.com/ns">Two</p>
  <ex:p id="delta" xmlns:ex="http://example.com/ns">Three</ex:p>
  <?pi 3.14159?>
</doc>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-namespace-uri-e" spec="XQuery">
               <fos:expression>namespace-uri($e//*[@id = 'alpha'])</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-e" spec="XQuery">
               <fos:expression>namespace-uri($e//*[@id = 'gamma'])</fos:expression>
               <fos:result>"http://example.com/ns"</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-e" spec="XQuery">
               <fos:expression>namespace-uri($e//*[@id = 'delta'])</fos:expression>
               <fos:result>"http://example.com/ns"</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-e" spec="XQuery">
               <fos:expression>namespace-uri($e//processing-instruction())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-e" spec="XQuery">
               <fos:expression>namespace-uri($e//*[@id = 'alpha']/text())</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-e" spec="XQuery">
               <fos:expression>namespace-uri($e//*[@id = 'alpha']/@id)</fos:expression>
               <fos:result>""</fos:result>
            </fos:test>
            <fos:test use="v-namespace-uri-e" spec="XQuery">
               <fos:expression>namespace-uri($e//*[@id = 'alpha']/@xml:id)</fos:expression>
               <fos:result>"http://www.w3.org/XML/1998/namespace"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="number" prefix="fn">
      <fos:signatures>
         <fos:proto name="number" return-type="xs:double">
            <fos:arg name="value" type="xs:anyAtomicType?" default="."/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value indicated by <code>$value</code> or, if <code>$value</code> is not
            specified, the context value after atomization, converted to an <code>xs:double</code>.
         </p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence or if <code>$value</code> cannot be converted
            to an <code>xs:double</code>, the <code>xs:double</code> value <code>NaN</code> is
            returned. </p>
         <p>Otherwise, <code>$value</code> is converted to an <code>xs:double</code> following the
            rules of <specref
               ref="casting-to-double"
               />. If the conversion to <code>xs:double</code>
            fails, the <code>xs:double</code> value <code>NaN</code> is returned.</p>
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <xerrorref spec="XP" class="DY" code="0002" type="type"
               />
            if <code>$value</code> is omitted and the context value is <xtermref
               ref="dt-absent" spec="DM40">absent</xtermref>.</p>
         <p>As a consequence of the rules given above, a type error is raised 
           <xerrorref spec="XP" class="TY" code="0004" type="type"/> if the context value
            cannot be atomized, or if the result of atomizing the context value is a sequence
            containing more than one atomic item.</p>
         <!-- bug 16745 -->
      </fos:errors>
      <fos:notes>
         <p>The string <code>+INF</code> is permitted as a representation of positive infinity,
            whether or not XSD 1.1 is supported. Similarly, <code>-0</code> and <code>0</code>
            produce negative zero and positive zero respectively.</p>
         <p>Generally <function>fn:number</function> returns <code>NaN</code> rather than raising a dynamic
            error if the argument cannot be converted to <code>xs:double</code>. However, a type
            error is raised in the usual way if the supplied argument cannot be atomized or if the
            result of atomization does not match the required argument type.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="e" id="v-number-e"><![CDATA[<e price="12.1" discount="NONE"/>]]></fos:variable>
         <fos:example>
            <fos:test>
               <fos:expression>number(12)</fos:expression>
               <fos:result>1.2e1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>number('12')</fos:expression>
               <fos:result>1.2e1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>number('INF')</fos:expression>
               <fos:result>xs:double('INF')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>number('NaN')</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>number('non-numeric')</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test use="v-number-e" spec="XQuery">
               <fos:expression>number($e/@price)</fos:expression>
               <fos:result>1.21e1</fos:result>
            </fos:test>
            <fos:test use="v-number-e" spec="XQuery">
               <fos:expression>number($e/@discount)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test use="v-number-e" spec="XQuery">
               <fos:expression>number($e/@misspelt)</fos:expression>
               <fos:result>xs:double('NaN')</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>("10", "11", "12") ! number()</fos:expression>
               <fos:result>1.0e1, 1.1e1, 1.2e1</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>

   </fos:function>
   <fos:function name="lang" prefix="fn">
      <fos:signatures>
         <fos:proto name="lang" return-type="xs:boolean">
            <fos:arg name="language" type="xs:string?"/>
            <fos:arg name="node" type="node()" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>This function tests whether the language of <code>$node</code>, or the context value if
            the second argument is omitted, as specified by <code>xml:lang</code> attributes is the
            same as, or is a sublanguage of, the language specified by <code>$language</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The language of the argument <code>$node</code> is determined by the value of the
            <code>xml:lang</code> attribute on the node, or, if the node has no such attribute,
            by the value of the
               <code>xml:lang</code> attribute on the nearest ancestor of the node that has an
               <code>xml:lang</code> attribute. If there is no such ancestor, then the function
            returns <code>false</code>. </p>

         <p>If <code>$language</code> is the empty sequence, it is interpreted as the zero-length
            string.</p>
         <p>The relevant <code>xml:lang</code> attribute is determined by the value of the XPath
            expression:</p>
         <eg xml:space="preserve">(ancestor-or-self::*/@xml:lang)[last()]</eg>
         <p>If this expression returns the empty sequence, the function returns <code>false</code>. </p>
         <p>Otherwise, the function returns <code>true</code> if and only if, based on a caseless
            default match as specified in section 3.13 of <bibref
               ref="Unicode"/>, either:</p>
         <olist>
            <item>
               <p>
                  <code>$language</code> is equal to the string-value of the relevant
                     <code>xml:lang</code> attribute, or</p>
            </item>
            <item>
               <p>
                  <code>$language</code> is equal to some substring of the string-value of the
                  relevant <code>xml:lang</code> attribute that starts at the start of the
                  string-value and ends immediately before a hyphen, <code>-</code>
                  (HYPHEN-MINUS, <code>#x002D</code>).</p>
            </item>
         </olist>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not a single node, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test spec="XQuery">
               <fos:expression>&lt;para xml:lang="en"/&gt; -> fn:lang("en")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression>&lt;div xml:lang="en"&gt;&lt;para&gt;And now, and
                        forever!&lt;/para&gt;&lt;/div&gt; -> fn:lang("en")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression>&lt;para xml:lang="EN"/&gt; -> fn:lang("en")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression>&lt;para xml:lang="en-us"/&gt; -> fn:lang("en")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression>&lt;para xml:lang="EN"/&gt; -> fn:lang("fr")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression>&lt;para xml:lang="en-us"/&gt; -> fn:lang("en-GB")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="path" prefix="fn">
      <fos:signatures>
         <fos:proto name="path" return-type="xs:string?">
            <fos:arg name="node" type="gnode()?" default="." usage="navigation"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a path expression that can be used to select the supplied node relative to the
            root of its containing document.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the function returns the empty sequence.</p>
         
         <p>The <code>$options</code> argument defines additional parameters controlling
            how the output is formatted. The <termref def="option-parameter-conventions"
               >option parameter conventions</termref> apply. The options available are as follows:</p>
         
         <fos:options>
            <fos:option key="origin">
               <fos:meaning>A GNode, which must be an ancestor of <code>$node</code>. If present,
                  the returned path will be a relative path that selects <code>$node</code>
                  starting from the supplied origin node, rather than from the root of the
                  containing tree.
               </fos:meaning>
               <fos:type>gnode()?</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="lexical">
               <fos:meaning>If true, the names of element nodes in the path are represented by the
                  result of a call on the <function>name</function> function applied to each element. The
                  result in this case does not contain sufficient information to identify the
                  namespace URI of the element.
               </fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="namespaces">
               <fos:meaning>A map from namespace prefixes to namespace URIs, such as might be returned
                  by the function <function>fn:in-scope-namespaces</function>. If a prefix is available
                  for a given URI, it is used in preference to using <code>Q{uri}local</code> notation.
               </fos:meaning>
               <fos:type>map((xs:NCName | enum('')), xs:anyURI)?</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="indexes">
               <fos:meaning>If true, the returned path includes the index positions of nodes. If
                  false, only the node names are included.
               </fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
            </fos:option>
         </fos:options>
         
         <p>Let <var>R</var> be the GNode supplied in the <code>origin</code> option,
         or the root GNode of the tree containing <code>$node</code> otherwise.</p>
         
         <p>If <code>$node</code> is a document node, or a JNode with no parent,
            the function returns the string <code>"/"</code>.</p>
         
         <p>Otherwise, the function returns a string that consists of a sequence of steps, one
            for each ancestor-or-self of <code>$node</code> that is not an ancestor-or-self 
            of <var>R</var>.</p>
         
         <p>If <var>R</var> is an XNode other than a document node and the <code>origin</code> option
            is absent or empty, then this string is preceded by
            a string notionally representing a call to the <code>fn:root</code> function, 
            expressed as follows:</p>
         
         <ulist>
            <item><p>If the <code>lexical</code> option is present with the value <code>true</code>,
            then the string <code>"fn:root()"</code>.</p></item>
            <item><p>If the <code>namespaces</code> option is present and defines a mapping from a 
               non empty prefix <var>P</var> 
            to the namespace URI <code>http://www.w3.org/2005/xpath-functions</code>, then
            <code>"<var>P</var>:root()"</code></p></item>
            <item><p>If the <code>namespaces</code> option is present and defines a mapping from the empty string
            to the namespace URI <code>http://www.w3.org/2005/xpath-functions</code>, then
            <code>"root()"</code></p></item>
            <item><p>Otherwise, <code>"Q{http://www.w3.org/2005/xpath-functions}root()"</code>.</p></item>
         </ulist>
            
         <p>Each step is the concatenation of:</p>
         
         <olist>
            <item><p>The character <code>"/"</code>, which is omitted for the first step
            if the <code>origin</code> option is present;</p></item>
            <item><p>A string whose form depends on the kind of node selected by that step, as
            follows:</p>
            <olist>
            <item>
               <p>For an element node, the concatenation of:</p>
               <olist>
                  <item><p>A representation of the element name, chosen as follows:</p>
                     <olist>
                        <item><p>If the <code>lexical</code> option is present with the value
                        <code>true</code>, then the result of applying the <function>name</function>
                        function to the element node.</p></item>
                        <item><p>Otherwise, if the <code>namespaces</code> option is present
                           and the element is in a namespace <var>U</var> and the <code>namespaces</code> option
                           includes a mapping from a prefix <var>P</var> to the namespace <var>U</var>,
                           then the string <code><var>P</var>:<var>L</var></code>, where <var>L</var>
                           is the local part of the element name.
                           If there is more than one such prefix, then one of them is chosen arbitrarily.</p>
                        </item>  
                        <item><p>Otherwise, if the <code>namespaces</code> option is present
                           and the element is in a namespace <var>U</var> and the <code>namespaces</code> option
                           includes a mapping from the zero-length string to the namespace <var>U</var>,
                           then the local part of the element name.</p>
                        </item> 
                        <item><p>Otherwise, if the <code>namespaces</code> option is present
                           and the element is in no namespace and the <code>namespaces</code> option
                           includes no mapping from the zero-length string to any namespace,
                           then the local part of the element name.</p>
                        </item>
                        <item><p>Otherwise, the string <code>Q{<var>U</var>}<var>L</var></code>,
                        where <var>U</var> is the namespace URI of the element name or the
                        empty string if the element is in no namespace, and <var>L</var> is
                        the local part of the element name.</p></item>
                     </olist>
                  </item>
                  <item><p>Unless the <code>indexes</code> option is present
                     with the value <code>false</code>,
                     a string in the form <code>[<var>position</var>]</code> where <var>position</var> is an
                        integer representing the one-based position of the selected node among its like-named
                        siblings.</p>
                  </item>
               </olist>
            </item>
            <item>
               <p>For an attribute node, the concatenation of:</p>
               <olist>
                  <item><p>The character <code>"@"</code></p></item>
                  <item><p>If the <code>lexical</code> option is present with the value
                        <code>true</code>, then the result of applying the <function>name</function>
                        function to the attribute node.</p></item>
                  <item>
                     <p>Otherwise, if the attribute node is in no namespace, the local part of the attribute name.</p>
                  </item>
                  <item><p>Otherwise, if the <code>namespaces</code> option is present, and if it includes a mapping
                        from a non-empty namespace prefix <var>P</var> to the namespace URI of the attribute, then
                        a string in the form <code><var>P</var>:<var>L</var></code>, where <var>L</var>
                           is the local part of the attribute name.
                           If there is more than one such prefix, then one of them is chosen arbitrarily.</p></item>
                  <item>
                     <p>Otherwise, the string <code>Q{<var>U</var>}<var>L</var></code>,
                        where <var>U</var> is the namespace URI of the attribute name, and <var>L</var> is
                        the local part of the attribute name.</p>

                  </item>
               </olist>
            </item>
            <item>
               <p>For a text node: <code>text()[<var>position</var>]</code> where
                        <code><var>position</var></code> is an integer representing the position
                  of the selected node among its text node siblings.</p>
               <p>The suffix <code>[<var>position</var>]</code> is omitted if the <code>indexes</code>
               option is present with the value <code>false</code>.</p>
            </item>
            <item>
               <p>For a comment node: <code>comment()[<var>position</var>]</code> where
                        <code><emph>position</emph></code> is an integer representing the position
                  of the selected node among its comment node siblings.</p>
               <p>The suffix <code>[<var>position</var>]</code> is omitted if the <code>indexes</code>
               option is present with the value <code>false</code>.</p>
            </item>
            <item>
               <p>For a processing-instruction node:
                        <code>processing-instruction(<var>local</var>)[<var>position</var>]</code>
                  where <code><emph>local</emph></code> is the name of the processing instruction
                  node and <code><emph>position</emph></code> is an integer representing the
                  position of the selected node among its like-named processing-instruction node
                  siblings.</p>
               <p>The suffix <code>[<var>position</var>]</code> is omitted if the <code>indexes</code>
               option is present with the value <code>false</code>.</p>
            </item>
            <item>
               
               <p>For a namespace node:</p>
               <olist>
                  <item>
                     <p>If the namespace node has a name:
                           <code>namespace::<emph>prefix</emph></code>, where
                              <code><emph>prefix</emph></code> is the local part of the name of the
                        namespace node (which represents the namespace prefix).</p>
                  </item>
                  <item>
                     <p>If the namespace node has no name (that is, if it represents the default
                        namespace):
                           <code>namespace::*[<var>U</var>local-name() = ""]</code></p>
                     <p>Here <code><var>U</var>local-name()</code> represents a call on the function
                        <code>fn:local-name</code> and is formatted using the same 
                        conventions as the call on <code>fn:root</code> described earlier.</p>
                  </item>
               </olist>
            </item>
               <item>
                  <p>For a JNode where the ·jvalue· property of the parent
                     is an array, then as the string <code>*[<var>N</var>]</code> where <var>N</var>
                     is the value of the ·jkey· property.</p>
               </item>
               <item><p>For any other JNode (including the case where the ·jvalue· property of the parent
                     is a map):</p>
                  <olist>
                     <item><p>If the value is an <code>xs:string</code>, <code>xs:untypedAtomic</code>,
                     or <code>xs:anyURI</code> that is castable to <code>xs:NCName</code>, then
                     the result of casting the value to <code>xs:NCName</code>.</p></item>
                     <item><p>If the value is an <code>xs:string</code>, <code>xs:untypedAtomic</code>,
                     or <code>xs:anyURI</code> that is not castable to <code>xs:NCName</code>, then
                     then as the string <code>get("<var>S</var>")</code>
                     where <var>S</var> is the string value.</p></item>
                     <item><p>If the value is numeric, then as the string <code>get(<var>N</var>)</code>
                     where <var>N</var> is the result of casting the numeric value to 
                        <code>xs:string</code>.</p></item>
                     <item><p>If the value is an <code>xs:QName</code>, then as the string
                     <code>get(#Q{<var>uri</var>}<var>local</var>)</code> where <var>uri</var>
                     and <var>local</var> are the namespace URI and local name parts of the QName.</p></item>
                     <item><p>If the value is an <code>xs:boolean</code>, then as the string
                     <code>get(true())</code> or <code>get(false())</code>.</p></item>
                     <item><p>If the value is of any other type, then as the string
                     <code>get(xs:<var>T</var>("<var>S</var>"))</code> where <var>T</var> is the
                        local part of the most specific built-in atomic type of which the value
                        is an instance, and <var>S</var> is the result of casting the value to 
                           <code>xs:string</code>.</p></item>
                  </olist>
                  
                  <p>TODO: Better handling of the case where the parent is neither a map nor an array,
                  for example where it is a sequence of several maps or several arrays. It's hard to
                  provide a better path for these when there is no AxisStep for selecting within
                  such values.</p>
                        
                     
               </item>
            </olist>
            </item>
            </olist>
 
            
         
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item></ulist>
            
               <p>If the value of the <code>origin</code> option is a node that is not an ancestor
                  of <code>$node</code> (or in the absence of <code>$node</code>, the context value), 
                  dynamic error <errorref spec="FO" class="PA" code="0001" type="dynamic"/>.</p>
         
      </fos:errors>
      
      <fos:notes>
         <p>Using the <code>namespaces</code> option to shorten the generated path is often convenient,
         but the resulting path may be unusable if the input tree contains multiple bindings for the same prefix.</p>
         
         <p>Similarly, using the <code>lexical</code> option is convenient if there is no need for precise
         namespace information: it is especially suitable when the containing node tree declares no namespaces.</p>
         
         <p>If the supplied argument is a map or an array, it will automatically be coerced to a JNode. This
         however is not useful, because this will be a root JNode, yielding the path <code>/</code>.</p>
         
      </fos:notes>
      
      <fos:examples>
         <fos:variable name="e" id="v-path-e"><![CDATA[document {            
  <p xmlns="http://example.com/one" xml:lang="de" author="Friedrich von Schiller">
Freude, schöner Götterfunken,<br/>
Tochter aus Elysium,<br/>
Wir betreten feuertrunken,<br/>
Himmlische, dein Heiligtum.
</p>}]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e)</eg></fos:expression>
               <fos:result>'/'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p)</eg></fos:expression>
               <fos:result>'/Q{http://example.com/one}p[1]'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p, { 'namespaces': in-scope-namespaces($e/*) })</eg></fos:expression>
               <fos:result>'/p[1]'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p, { 'indexes': false() })</eg></fos:expression>
               <fos:result>'/Q{http://example.com/one}p'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p/@xml:lang)</eg></fos:expression>
               <fos:result>'/Q{http://example.com/one}p[1]/@Q{http://www.w3.org/XML/1998/namespace}lang'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e//@xml:lang, { 'namespaces': in-scope-namespaces($e/*) })</eg></fos:expression>
               <fos:result>'/p[1]/@xml:lang'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p/@author)</eg></fos:expression>
               <fos:result>'/Q{http://example.com/one}p[1]/@author'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p/*:br[2])</eg></fos:expression>
               <fos:result>'/Q{http://example.com/one}p[1]/Q{http://example.com/one}br[2]'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p/*:br[2], {
  'namespaces': { 'N': 'http://example.com/one' },
  'indexes': false() 
})</eg></fos:expression>
               <fos:result>'/N:p/N:br'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e//text()[starts-with(normalize-space(), 'Tochter')])</eg></fos:expression>
               <fos:result>'/Q{http://example.com/one}p[1]/text()[2]'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p/*:br[2], { 'lexical': true() })</eg></fos:expression>
               <fos:result>'/p[1]/br[2]'</fos:result>
            </fos:test>
            <fos:test use="v-path-e" spec="XQuery">
               <fos:expression><eg>path($e/*:p/*:br[2], { 'lexical': true(), 'origin': $e/*:p })</eg></fos:expression>
               <fos:result>'br[2]'</fos:result>
            </fos:test>
         </fos:example>
         <fos:variable name="emp" id="v-path-emp" as="element()"><![CDATA[
  <employee xml:id="ID21256">
     <empnr>E21256</empnr>
     <first>John</first>
     <last>Brown</last>
  </employee>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-path-emp" spec="XQuery">
               <fos:expression><eg>path($emp)</eg></fos:expression>
               <fos:result>'Q{http://www.w3.org/2005/xpath-functions}root()'</fos:result>
            </fos:test>
            <fos:test use="v-path-emp" spec="XQuery">
               <fos:expression><eg>path($emp/@xml:id)</eg></fos:expression>
               <fos:result>'Q{http://www.w3.org/2005/xpath-functions}root()/@Q{http://www.w3.org/XML/1998/namespace}id'</fos:result>
            </fos:test>
            <fos:test use="v-path-emp" spec="XQuery">
               <fos:expression><eg>path($emp/empnr)</eg></fos:expression>
               <fos:result>'Q{http://www.w3.org/2005/xpath-functions}root()/Q{}empnr[1]'</fos:result>
            </fos:test>
            <fos:test use="v-path-emp" spec="XQuery">
               <fos:expression><eg>path($emp/empnr, { 'lexical': true() })</eg></fos:expression>
               <fos:result>'fn:root()/empnr[1]'</fos:result>
            </fos:test>
            <fos:test use="v-path-emp" spec="XQuery">
               <fos:expression><eg>path($emp/empnr, {
  'namespaces': {
    'fn': 'http://www.w3.org/2005/xpath-functions',
    '': ''
  }
})</eg></fos:expression>
               <fos:result>'fn:root()/empnr[1]'</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $in := [ { "b": [ 3, 4 ] } ]
return path($in/*[1]/b/*[2])</eg></fos:expression>
               <fos:result>"/*[1]/b/*[2]"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>let $in := [ [ { 'a': 1 } ], [ { 'a': 2 } ] ]
return path($in//a[. = 2])</eg></fos:expression>
               <fos:result>"/*[2]/*[1]/a"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="332 1660" PR="1620 1886" date="2024-11-29">
            <p>Options are added to customize the form of the output.</p>
         </fos:change>
         <fos:change issue="2100" PR="2149" date="2025-08-05">
            <p>The function is extended to handle JNodes.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="root" prefix="fn">
      <fos:signatures>
         <fos:proto name="root" return-type="gnode()?">
            <fos:arg name="node" type="gnode()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the root of the tree to which <code>$node</code> belongs. The
         function can be applied both to <xtermref spec="DM40" ref="dt-XNode">XNodes</xtermref>
         and to <xtermref spec="DM40" ref="dt-JNode">JNodes</xtermref>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the value of the expression
               <code>$node/ancestor-or-self::gnode()[last()]</code>.</p>
         
        
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type
               <code>gnode()?</code>, type error
               <xerrorref spec="XP" class="TY" code="0004" type="type"/>.</p>
            </item>
         </ulist>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <p>These examples use some variables which could be defined in <bibref ref="xquery-40"
               />
               as:</p>
         </fos:example>
         <fos:example>
            <eg xml:space="preserve">let $i := &lt;tool&gt;wrench&lt;/tool&gt;
let $o := &lt;order&gt;{ $i }&lt;quantity&gt;5&lt;/quantity&gt;&lt;/order&gt;
let $odoc := document { $o }
let $newi := $o/tool</eg>
         </fos:example>
         <fos:example>
            <p>Or they could be defined in <bibref ref="xslt-40"/> as:</p>
         </fos:example>
         <fos:example>
            <eg xml:space="preserve">&lt;xsl:variable name="i" as="element()"&gt;
  &lt;tool&gt;wrench&lt;/tool&gt;
&lt;/xsl:variable&gt;

&lt;xsl:variable name="o" as="element()"&gt;
  &lt;order&gt;
    &lt;xsl:copy-of select="$i"/&gt;
    &lt;quantity&gt;5&lt;/quantity&gt;
  &lt;/order&gt;
&lt;/xsl:variable&gt;

&lt;xsl:variable name="odoc"&gt;
  &lt;xsl:copy-of select="$o"/&gt;
&lt;/xsl:variable&gt;

&lt;xsl:variable name="newi" select="$o/tool"/&gt;</eg>
         </fos:example>
         <fos:example>
            <p><code>root($i)</code> returns the element node <code>$i</code>
            </p>
         </fos:example>
         <fos:example>
            <p><code>root($o/quantity)</code> returns the element node <code>$o</code>
            </p>
         </fos:example>
         <fos:example>
            <p><code>root($odoc//quantity)</code> returns the document node <code>$odoc</code>
            </p>
         </fos:example>
         <fos:example>
            <p><code>root($newi)</code> returns the element node <code>$o</code>
            </p>
         </fos:example>
         <fos:example>
            <p>The final three examples could be made type-safe by wrapping their operands with
                  <code>exactly-one()</code>.</p>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="has-children" prefix="fn">
      <fos:signatures>
         <fos:proto name="has-children" return-type="xs:boolean">
            <fos:arg name="node" type="gnode()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the supplied GNode has one or more child nodes (of any kind).</p>
      </fos:summary>
      <fos:rules>
         <p>Provided that the supplied argument <code>$node</code> matches the expected type
               <code>gnode()?</code>, the result of the function call
               <code>fn:has-children($node)</code> is defined to be the same as the result of the
            expression <code>fn:exists($node/child::gnode())</code>.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>gnode()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>If <code>$node</code> is the empty sequence, the result is <code>false</code>.</p>
         <p>The motivation for this function is to support streamed evaluation. According to the
            streaming rules in <bibref
               ref="xslt-40"/>, the following construct is not
            streamable:</p>
         <eg><![CDATA[
<xsl:if test="exists(row)">
  <ulist>
    <xsl:for-each select="row">
      <item><xsl:value-of select="."/></item>
    </xsl:for-each>
  </ulist>
</xsl:if>  
]]></eg>
         <p>This is because it makes two downward selections to read the child <code>row</code>
            elements. The use of <function>fn:has-children</function> in the <code>xsl:if</code> conditional
            is intended to circumvent this restriction.</p>
         <p>Although the function was introduced to support streaming use cases, it has general
            utility as a convenience function.</p>
         <p>If the supplied argument is a map or an array, it will automatically be coerced to a JNode.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="e" id="v-has-children-e"><![CDATA[<doc>
  <p id="alpha">One</p>
  <p/>
  <p>Three</p>
  <?pi 3.14159?>
</doc>]]>
         </fos:variable>
         <fos:example>
            <fos:test use="v-has-children-e" spec="XQuery">
               <fos:expression>has-children($e)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test use="v-has-children-e" spec="XQuery">
               <fos:expression>has-children($e//p[1])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test use="v-has-children-e" spec="XQuery">
               <fos:expression>has-children($e//p[2])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test use="v-has-children-e" spec="XQuery">
               <fos:expression>has-children($e//p[3])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test use="v-has-children-e" spec="XQuery">
               <fos:expression>has-children($e//processing-instruction())</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test use="v-has-children-e" spec="XQuery">
               <fos:expression>has-children($e//p[1]/text())</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test use="v-has-children-e" spec="XQuery">
               <fos:expression>has-children($e//p[1]/@id)</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>jtree([1,2,3]) => has-children()</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>jtree([]) => has-children()</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2100" PR="2149" date="2025-08-12">
            <p>Generalized to work with JNodes as well as XNodes.</p>
         </fos:change>
      </fos:changes>
      
   </fos:function>
   
   
   
   
   
   <fos:function name="distinct-ordered-nodes" prefix="fn">
      <fos:signatures>
         <fos:proto name="distinct-ordered-nodes" return-type="gnode()*">
            <fos:arg name="nodes" type="gnode()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Removes duplicate GNodes and sorts the input into document order.</p>
      </fos:summary>
      <fos:rules>
         <p>Any duplicate GNodes (that is, XNodes or JNodes) in the input 
            (based on node identity) are discarded. The remaining GNodes
         are returned in <xtermref spec="XP40" ref="dt-document-order">document order</xtermref>.</p>
      </fos:rules>
      <fos:notes>
         <p>Document order is <termref def="implementation-dependent"/> (but stable) for
         GNodes in different trees. If some GNode in tree <var>A</var>
         precedes some GNode in tree <var>B</var>, then every GNode in <var>A</var> precedes
         every GNode in <var>B</var>.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
let $x := parse-xml('<doc><a/><b/><c/><d/><c/><e/></doc>')
return distinct-ordered-nodes(($x//c, $x//b, $x//a, $x//b)) ! name()
               ]]></eg></fos:expression>
               <fos:result>"a", "b", "c", "c"</fos:result>
               <fos:postamble>The two <code>$x//b</code> expressions select the same node; one of these
               is eliminated as a duplicate. The <code>$x//c</code> expression selects two nodes
               that have distinct identity, so both are retained.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[
let $x := [ 1, "a", true() ]
return count(distinct-ordered-nodes(
  ($x/*[1], $x/jnode(*, xs:integer)) 
)) 
               ]]></eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>The first array member is selected by two different
                  routes; duplicate JNodes are eliminated.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1189" PR="1191" date="2024-05-14"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="innermost" prefix="fn">
      <fos:signatures>
         <fos:proto name="innermost" return-type="gnode()*">
            <fos:arg name="nodes" type="gnode()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns every GNode within the input sequence that is not an ancestor of another member
            of the input sequence; the GNodes are returned in document order with duplicates
            eliminated.</p>
      </fos:summary>
      <fos:rules>
         <p>The effect of the function call <code>fn:innermost($nodes)</code> is defined to be
            equivalent to the result of the expression:</p>
         <eg>$nodes except $nodes/ancestor::gnode()</eg>
         <p>That is, the function takes as input a sequence of GNodes, and returns every GNode within
            the sequence that is not an ancestor of another GNode within the sequence; the GNodes are
            returned in document order with duplicates eliminated.</p>
      </fos:rules>
      <fos:notes>
         <p>If the supplied argument includes a map or an array, it will automatically be coerced to a JNode.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
"<doc><div id='a'><div id='b'><div id='c'/></div></div></doc>"
-> parse-xml(.)//div
-> innermost(.)
-> for-each(., fn { string(@id) })
               ]]></eg></fos:expression>
               <fos:result><code>"c"</code></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[
[ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ]
  //jnode(*, array(*))
=> innermost() =!> jvalue()
               ]]></eg></fos:expression>
               <fos:result><code>[ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ]</code></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2100" PR="2149" date="2025-08-12">
            <p>Generalized to work with JNodes as well as XNodes.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="outermost" prefix="fn">
      <fos:signatures>
         <fos:proto name="outermost" return-type="gnode()*">
            <fos:arg name="nodes" type="gnode()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns every GNode within the input sequence that has no ancestor that is itself a
            member of the input sequence; the nodes are returned in document order with duplicates
            eliminated.</p>
      </fos:summary>
      <fos:rules>
         <p>The effect of the function call <code>fn:outermost($nodes)</code> is defined to be
            equivalent to the result of the expression:</p>
         <eg>$nodes[not(ancestor::gnode() intersect $nodes)]/.</eg>
         <!--bug 17029-->
         <p>That is, the function takes as input a sequence of GNodes, and returns every GNode within
            the sequence that does not have another GNode within the sequence as an ancestor; the
            GNodes are returned in document order with duplicates eliminated.</p>
      </fos:rules>
      <fos:notes>
         <p>The formulation <code>$nodes except $nodes/descendant::node()</code> might appear to be
            simpler, but does not correctly account for attribute nodes, as these are not
            descendants of their parent element.</p>
         <p>The motivation for the function was based on XSLT streaming use cases. There are cases
            where the <bibref
               ref="xslt-40"
               /> streaming rules allow the construct
               <code>outermost(//section)</code> but do not allow <code>//section</code>; the
            function can therefore be useful in cases where it is known that sections will not be
            nested, as well as cases where the application actually wishes to process all sections
            except those that are nested within another.</p>
         <p>If the supplied argument includes a map or an array, it will automatically be coerced to a JNode.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
"<doc><div id='a'><div id='b'><div id='c'/></div></div></doc>"
-> parse-xml(.)//div
-> outermost(.)
-> for-each(., fn { string(@id) })
               ]]></eg></fos:expression>
               <fos:result><code>"a"</code></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[
[ [ [ 1 ], [ 2 ] ], [ [ 3 ], [ 4 ] ], [ [ 5 ], [ 6 ] ] ]
  //self::jnode(*, array(*))
=> outermost() =!> array:size()
               ]]></eg></fos:expression>
               <fos:result><code>3</code></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2100" PR="2149" date="2025-08-12">
            <p>Generalized to work with JNodes as well as XNodes.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="index-of" prefix="fn">
      <fos:signatures>
         <fos:proto name="index-of" return-type="xs:integer*">
            <fos:arg name="input" type="xs:anyAtomicType*"/>
            <fos:arg name="target" type="xs:anyAtomicType"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence of positive integers giving the positions within the sequence
               <code>$input</code> of items that are <termref def="dt-contextually-equal"/> 
            to <code>$target</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence of positive integers giving the 1-based positions within the
            sequence <code>$input</code> of items that are <termref def="dt-contextually-equal"/> 
            to <code>$target</code>.</p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"
            />. This collation is used when string comparison is
            required.</p>
         
         <p>The result sequence is in ascending numeric order.</p>
      </fos:rules>
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, or if no item in
            <code>$input</code> matches <code>$target</code>, then the function returns the empty
            sequence.</p>
         <p>No error occurs if non-comparable values are encountered. So when comparing two atomic
            items, the effective boolean value of <code>fn:index-of($a, $b)</code> is <code>true</code> if
               <code>$a</code> and <code>$b</code> are equal, <code>false</code> if they are not equal or not
            comparable.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>index-of((10, 20, 30, 40), 35)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>index-of((10, 20, 30, 30, 20, 10), 20)</fos:expression>
               <fos:result>2, 5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>index-of(
  ("a", "sport", "and", "a", "pastime"),
  "a"
)</eg></fos:expression>
               <fos:result>1, 4</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>index-of(
  ("a", "b", "c"),
  "B",
  "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
)</eg></fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>index-of(current-date(), 23)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>index-of([ 1, [ 5, 6 ], [ 6, 7 ] ], 6)</fos:expression>
               <fos:result>3, 4</fos:result>
               <fos:postamble>The array is atomized to a sequence of five integers</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>If <code>@a</code> is an attribute of type <code>xs:NMTOKENS</code> whose string
               value is <code>"red green blue"</code>, and whose typed value is therefore
                  <code>("red", "green", "blue")</code>, then <code>fn:index-of(@a, "blue")</code>
               returns <code>3</code>. This is because the function calling mechanism atomizes the
               attribute node to produce a sequence of three <code>xs:NMTOKEN</code> values.</p>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2216" PR="2256" date="2025-12-01"><p>In the interests of consistency,
         the <function>index-of</function> function now defines equality to mean
         <termref def="dt-contextually-equal"/>. This has the implication that
         <code>NaN</code> is now considered equal to <code>NaN</code>.</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="empty" prefix="fn">
      <fos:signatures>
         <fos:proto name="empty" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the argument is the empty sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is the empty sequence, the function returns
               <code>true</code>; otherwise, the function returns <code>false</code>. </p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
count($input) eq 0
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>empty((1, 2, 3)[10])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>empty(remove(("hello", "world"), 1))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>empty([])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>empty({})</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>empty("")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Assuming <code>$break</code> is an element with no children:</p>
            <eg>
let $break := &lt;br/&gt;
return empty($break)
            </eg>
            <p>The result is <code>false</code>.</p>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="siblings" prefix="fn">
      <fos:signatures>
         <fos:proto name="siblings" return-type="gnode()*">
            <fos:arg name="node" type="gnode()?" default="." usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the supplied GNode together with its siblings, in document order.</p>
      </fos:summary>
      <fos:rules>
         <p>If the value of <code>$node</code> is the empty sequence, the function returns the empty sequence.</p>
         
         <p>If <code>$node</code> is a child of some parent GNode <var>P</var>, the function returns all the
         children of <var>P</var> (including <code>$node</code>), in document order, as determined
            by the value of <code>$node/child::gnode()</code>.</p>
         
         <p>Otherwise (specifically, if <code>$node</code> is parentless, or if it is an attribute or namespace node),
         the function returns <code>$node</code>.</p>
         
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
if ($node intersect $node/parent::node()/child::node())
then $node/parent::node()/child::node()
else $node
      </fos:equivalent>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>node()?</code>, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>The result of <code>siblings($n)</code> (except in error cases) is the same as
         the result of <code>$n/(preceding-sibling::node() | following-sibling-or-self::node())</code>.
         It is also the same as <code>$n/(preceding-sibling-or-self::node() | following-sibling::node())</code></p>
         <p>As with names such as <code>parent</code> and <code>child</code>, the word <term>sibling</term>
         used here as a technical term is not a precise match to its use in describing human family relationships,
         but is chosen for convenience.</p>
      </fos:notes>
      
      <fos:examples>
         <fos:variable name="e" id="v-siblings-e"><![CDATA[<doc x="X"><a>A</a>text<?pi 3.14159?></doc>]]></fos:variable>
         <fos:example>
            <fos:test use="v-siblings-e" spec="XQuery">
               <fos:expression>siblings($e//a) ! string()</fos:expression>
               <fos:result>"A", "text", "3.14159"</fos:result>
            </fos:test>
            <fos:test use="v-siblings-e" spec="XQuery">
               <fos:expression>siblings($e//processing-instruction('pi')) ! string()</fos:expression>
               <fos:result>"A", "text", "3.14159"</fos:result>
            </fos:test>
            <fos:test use="v-siblings-e" spec="XQuery">
               <fos:expression>siblings($e//@x) ! string()</fos:expression>
               <fos:result>"X"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1542 1552" PR="1547 1551" date="2024-11-05"><p>New in 4.0</p></fos:change>
      </fos:changes>

   </fos:function>
   
   <fos:function name="exists" prefix="fn">
      <fos:signatures>
         <fos:proto name="exists" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the argument is a non-empty sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is a non-empty sequence, the function returns
               <code>true</code>; otherwise, the function returns <code>false</code>. </p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
count($input) gt 0
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>exists(remove(("hello"), 1))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>exists(remove(("hello", "world"), 1))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>exists([])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>exists({})</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>exists("")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Assuming <code>$break</code> is an element with no children:</p>
            <eg>
let $break := &lt;br/>
return exists($break)
            </eg>
            <p>The result is <code>true</code>.</p>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="distinct-values" prefix="fn">
      <fos:signatures>
         <fos:proto name="distinct-values" return-type="xs:anyAtomicType*">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the values that appear in a sequence, with duplicates eliminated.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the sequence that results from removing from <code>$values</code> all
            but one of a set of values that are 
            <termref def="dt-contextually-equal"/> to one another,
            when compared using the collation selected according to the rules in <specref
                  ref="choosing-a-collation"/> and the implicit timezone from the dynamic context.
            </p>


         <p>The ordering of the result is as follows:</p>
         
         <ulist>
            <item><p>For any set of values that compare equal, the one that is
            returned is the one that appears first in <code>$values</code>.</p></item>
            <item><p>The items that are returned appear in the order of their first 
            appearance within <code>$values</code>.</p></item>
         </ulist>

         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter($values, 
  fn($item, $pos) {
    empty(
      filter(
        subsequence($values, 1, $pos - 1),
        deep-equal(?, $item, $collation)
      )
    )
  }
)            
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$values</code> is the empty sequence, the function returns the empty sequence.</p>

         <p>Values of type <code>xs:untypedAtomic</code> are compared as if they were of type
            <code>xs:string</code>.</p>
         <p>Values that cannot be compared, because the <code>eq</code> operator is not defined for
            their types, are considered to be distinct.</p>

         <p>For numeric values, the rules are the same as <function>fn:atomic-equal</function>:
            positive and negative zero are treated as equal, <code>NaN</code> is treated
            as equal to <code>NaN</code>, and values of different numeric types are converted
            to unlimited-precision decimals for comparison purposes.</p>
         <p> If <code>xs:dateTime</code>, <code>xs:date</code> or <code>xs:time</code> values do not
            have a timezone, they are considered to have the implicit timezone provided by the
            dynamic context for the purpose of comparison. Note that <code>xs:dateTime</code>,
            <code>xs:date</code> or <code>xs:time</code> values can compare equal even if their
            timezones are different.</p>
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>distinct-values((1, 2.0, 3, 2))</fos:expression>
               <fos:result>1, 2.0, 3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>distinct-values((
  xs:untypedAtomic("cherry"),
  xs:untypedAtomic("plum"),
  xs:untypedAtomic("plum")
))</eg></fos:expression>
               <fos:result>xs:untypedAtomic("cherry"), xs:untypedAtomic("plum")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change><p>Changed in 4.0 to use transitive equality comparisons for numeric
         values.</p>
         </fos:change>
         <fos:change issue="628" PR="987" date="2024-02-06"><p>The order of results is now prescribed; 
            it was previously implementation-dependent.</p></fos:change>
         <fos:change issue="2139" PR="2168" date="2025-08-14"><p>Atomic items of types <code>xs:hexBinary</code> 
            and <code>xs:base64Binary</code> are now mutually comparable. In rare cases, where an
            application uses both types and assumes they are distinct, this can represent a backwards
            incompatibility.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="duplicate-values" prefix="fn">
      <fos:signatures>
         <fos:proto name="duplicate-values" return-type="xs:anyAtomicType*">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the values that appear in a sequence more than once.</p>
      </fos:summary>
      <fos:rules>
         <p>The items of <code>$values</code> are compared against each other, according to the
            rules of <function>fn:distinct-values</function> and with <code>$collation</code> as the collation
            selected according to the rules in <specref ref="choosing-a-collation"/>.</p>
         <p>From each resulting set of values that are considered equal, one value will be
            returned if the set contains more than one value.</p>
         
         <p>Specifically, the function returns those items in <code>$values</code> that are
         <termref def="dt-contextually-equal"/> to exactly one item appearing earlier in the sequence.</p>
         
         <p>This means that the ordering of the result is as follows:</p>
         
         <ulist>
            <item><p>For any set of values that compare equal, the one that is
               returned is the one that appears second in <code>$values</code>.</p></item>
            <item><p>The items that are returned appear in the order of their second
               appearance within <code>$values</code>.</p></item>
         </ulist>
         
        
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter(
  $values, 
  fn($item, $pos) {
    count(
      filter(
        subsequence($values, 1, $pos - 1),
        deep-equal(?, $item, $collation)
      )
    ) eq 1
  }
)            
      </fos:equivalent>
      
      <fos:notes>
         <p>The comparison rules are exactly the same as the <function>fn:distinct-values</function>
         function.</p>
      </fos:notes>
      
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>duplicate-values((1, 2, 3, 1.0, 1e0))</fos:expression>
               <fos:result>1.0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>duplicate-values(1 to 100)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test spec="XQuery">
               <fos:expression><![CDATA[duplicate-values(('1', <x>1</x>, '2', 2))]]></fos:expression>
              <fos:result>xs:untypedAtomic("1")</fos:result>
               <fos:postamble>The string <code>"1"</code> and the untyped value of the
                  element node are considered equal, whereas the string <code>"2"</code>
                  and the integer are considered unequal.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Raise an error for duplicates in an ID sequence:</p>
               <eg>let $ids := duplicate-values(//@id)
where exists($ids)
return error((), 'Duplicate IDs found: ' || string-join($ids, ', '))</eg>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="123 628 1869" PR="614 987" date="2023-07-18"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="identity" prefix="fn">
      <fos:signatures>
         <fos:proto name="identity" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns its argument value.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>$input</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
         $input
      </fos:equivalent>
      <fos:notes>
         <p>The function is useful in contexts where a function must be supplied, but no processing is required.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>identity(0)</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>identity(1 to 10)</fos:expression>
               <fos:result>1, 2, 3, 4, 5, 6, 7, 8, 9, 10</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><![CDATA[parse-xml('<a/>') ! (identity(/) is /)]]></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>If the argument is a node, the function returns the identical node, not a copy</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>identity(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20" issue="858" PR="1473"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="insert-before" prefix="fn">
      <fos:signatures>
         <fos:proto name="insert-before" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="position" type="xs:integer"/>
            <fos:arg name="insert" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence constructed by inserting an item or a sequence of items at a given
            position within an existing sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>The value returned by the function consists of all items of <code>$input</code> whose
            1-based position is less than <code>$position</code>, followed by all items of
               <code>$insert</code>, followed by the remaining elements of <code>$input</code>, in
            that order. </p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter($input, fn($item, $pos) { $pos lt $position }),
$insert,
filter($input, fn($item, $pos) { $pos ge $position })
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, <code>$insert</code> is returned. If
               <code>$insert</code> is the empty sequence, <code>$input</code> is returned.</p>
         <p>If <code>$position</code> is less than one (1), the first position, the effective value
            of <code>$position</code> is one (1). If <code>$position</code> is greater than the
            number of items in <code>$input</code>, then the effective value of
               <code>$position</code> is equal to the number of items in <code>$input</code> plus
            1. </p>
         <p>The value of <code>$input</code> is not affected by the sequence construction.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable id="v-insert-before-abc" name="abc"
            select="(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;)"/>
         <fos:example>
            <fos:test use="v-insert-before-abc">
               <fos:expression>insert-before($abc, 0, "z")</fos:expression>
               <fos:result>"z", "a", "b", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-insert-before-abc">
               <fos:expression>insert-before($abc, 1, "z")</fos:expression>
               <fos:result>"z", "a", "b", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-insert-before-abc">
               <fos:expression>insert-before($abc, 2, "z")</fos:expression>
               <fos:result>"a", "z", "b", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-insert-before-abc">
               <fos:expression>insert-before($abc, 3, "z")</fos:expression>
               <fos:result>"a", "b", "z", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-insert-before-abc">
               <fos:expression>insert-before($abc, 4, "z")</fos:expression>
               <fos:result>"a", "b", "c", "z"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="remove" prefix="fn">
      <fos:signatures>
         <fos:proto name="remove" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="positions" type="xs:integer*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a new sequence containing all the items of <code>$input</code> <phrase diff="chg" at="2023-01-17">except those
            at specified positions</phrase>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence consisting of all items of <code>$input</code> <phrase diff="chg" at="2023-01-17">whose
            1-based position is not equal to any of the integers in <code>$positions</code>. </phrase></p>
        
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter($input, fn($item, $pos) { not($pos = $positions) })
      </fos:equivalent>
      <fos:notes>
         <p diff="chg" at="2023-01-17">Any integer in <code>$positions</code> that is less than 1 or greater than the number of items in
               <code>$input</code> is effectively ignored.</p>
         <p>If <code>$input</code> is the empty sequence, the empty sequence is returned.</p>
         <p diff="add" at="2023-01-17">If <code>$positions</code> is the empty sequence, the input sequence <code>$input</code> is returned unchanged.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable id="v-remove-abc" name="abc"
            select="(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;)"/>
         <fos:example>
            <fos:test use="v-remove-abc">
               <fos:expression>remove($abc, 0)</fos:expression>
               <fos:result>"a", "b", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-remove-abc">
               <fos:expression>remove($abc, 1)</fos:expression>
               <fos:result>"b", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-remove-abc">
               <fos:expression>remove($abc, 6)</fos:expression>
               <fos:result>"a", "b", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-remove-abc">
               <fos:expression>remove((), 3)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-remove-abc">
               <fos:expression>remove($abc, 2 to 3)</fos:expression>
               <fos:result>"a"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-remove-abc">
               <fos:expression>remove($abc, ())</fos:expression>
               <fos:result>"a", "b", "c"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="294" PR="313" date="2023-01-24">
            <p>The second argument can now be a sequence of integers.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="head" prefix="fn">
      <fos:signatures>
         <fos:proto name="head" return-type="item()?">
            <fos:arg name="input" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the first item in a sequence. </p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the first item in <code>$input</code>; if <code>$input</code>
         is empty, it returns the empty sequence.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter($input, fn($item, $pos) { $pos eq 1 })
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>head(1 to 5)</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>head(("a", "b", "c"))</fos:expression>
               <fos:result>"a"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>head(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>head([ 1, 2, 3 ])</fos:expression>
               <fos:result>[ 1, 2, 3 ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="tail" prefix="fn">
      <fos:signatures>
         <fos:proto name="tail" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns all but the first item in a sequence. </p>
      </fos:summary>
      <fos:rules>
         <p>The function all items in <code>$input</code> except the first, retaining order.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter($input, fn($item, $pos) { $pos gt 1 })
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, or a sequence containing a single item, then
            the empty sequence is returned. </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>tail(1 to 5)</fos:expression>
               <fos:result>2, 3, 4, 5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tail(("a", "b", "c"))</fos:expression>
               <fos:result>"b", "c"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tail("a")</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tail(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>tail([ 1, 2, 3 ])</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="trunk" prefix="fn">
      <fos:signatures>
         <fos:proto name="trunk" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns all but the last item in a sequence. </p>
      </fos:summary>
      <fos:rules>
         <p>The function returns all items in <code>$input</code> except the last, retaining order.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter($input, fn($item, $pos) { $pos ne count($input) })
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, or a sequence containing a single item, then
            the empty sequence is returned. </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>trunk(1 to 5)</fos:expression>
               <fos:result>1, 2, 3, 4</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>trunk(("a", "b", "c"))</fos:expression>
               <fos:result>"a", "b"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>trunk("a")</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>trunk(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>trunk([ 1, 2, 3 ])</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="97" PR="250" date="2022-12-07"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="replicate" prefix="fn">
      <fos:signatures>
         <fos:proto name="replicate" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="count" type="xs:nonNegativeInteger"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Produces multiple copies of a sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the value of <code>(1 to $count) ! $input</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
for-each(1 to $count, fn($item, $pos) { $input })
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, the empty sequence is returned.</p>
         <p>The <code>$count</code> argument is declared as <code>xs:nonNegativeInteger</code>,
         which means that a type error occurs if it is called with a negative value.</p>
         <p>If the input sequence contains nodes, these are not copied: instead, the result sequence contains
         multiple references to the same node. So, for example, <code>fn:count(fn:replicate(/, 6)|())</code>
         returns <code>1</code>, because the <function>fn:replicate</function> call creates duplicates, and the
            union operation eliminates them.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>replicate(0, 6)</fos:expression>
               <fos:result>0, 0, 0, 0, 0, 0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>replicate(("A", "B", "C"), 3)</fos:expression>
               <fos:result>"A", "B", "C", "A", "B", "C", "A", "B", "C"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>replicate((), 5)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>replicate(("A", "B", "C"), 1)</fos:expression>
               <fos:result>"A", "B", "C"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>replicate(("A", "B", "C"), 0)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>        
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-10-04"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="insert-separator" prefix="fn">
      <fos:signatures>
         <fos:proto name="insert-separator" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="separator" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Inserts a separator between adjacent items in a sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>The function inserts a separator between adjacent items in a sequence.
            The input is returned unchanged if <code>$separator</code> is the empty sequence
            or if <code>$input</code> contains less than two items.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
for-each($input, fn($item, $pos) {
  if ($pos gt 1) { $separator },
  $item
})
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>insert-separator(1 to 5, "|")</fos:expression>
               <fos:result>1, "|", 2, "|" , 3, "|", 4, "|", 5</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>insert-separator((), "|")</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>insert-separator("A", "|")</fos:expression>
               <fos:result>"A"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>insert-separator(1 to 3, ("⅓", "⅔"))</fos:expression>
               <fos:result>1, "⅓", "⅔", 2, "⅓", "⅔", 3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Insert an empty <code>hr</code> element between adjacent paragraphs:</p>
            <eg><![CDATA[insert-separator(./para, <hr/>)]]></eg>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2 868 2327" PR="1504 2329" date="2022-09-27"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   
   <fos:function name="foot" prefix="fn">
      <fos:signatures>
         <fos:proto name="foot" return-type="item()?">
            <fos:arg name="input" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the last item in a sequence. </p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the value of the expression <code>$input[last()]</code></p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter($input, fn($item, $pos) { $pos eq count($input) })
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, the empty sequence is returned. </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>foot(1 to 5)</fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>foot(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="97" PR="250" date="2022-12-07"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
 

   <fos:function name="reverse" prefix="fn">
      <fos:signatures>
         <fos:proto name="reverse" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Reverses the order of items in a sequence. </p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence containing the items in <code>$input</code> in reverse
            order.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
fold-left($input, (), fn($result, $item) { $item, $result })
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, the empty sequence is returned. </p>
      </fos:notes>
      <fos:examples>
         <fos:variable id="v-reverse-abc" name="abc"
            select="(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;)"/>
         <fos:example>
            <fos:test use="v-reverse-abc">
               <fos:expression>reverse($abc)</fos:expression>
               <fos:result>"c", "b", "a"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>reverse(("hello"))</fos:expression>
               <fos:result>"hello"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>reverse(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>reverse([ 1, 2, 3 ])</fos:expression>
               <fos:result>[ 1, 2, 3 ]</fos:result>
               <fos:postamble>The input is a sequence containing a single item (the array)</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>reverse(([ 1, 2, 3 ], [ 4, 5, 6 ]))</fos:expression>
               <fos:result>[ 4, 5, 6 ], [ 1, 2, 3 ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="subsequence" prefix="fn">
      <fos:signatures>
         <fos:proto name="subsequence" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="start" type="xs:double"/>
            <fos:arg name="length" type="xs:double?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the contiguous sequence of items in <code>$input</code>
            beginning at the position indicated by <code>$start</code> and
            continuing for the number of items indicated by <code>$length</code>. </p>
      </fos:summary>
      <fos:rules>
         <p>If the third argument is the empty sequence, the function returns:</p>
         <eg xml:space="preserve">$input[round($start) le position()]</eg>
         <p>Otherwise, the function returns:</p>
         <eg xml:space="preserve">$input[round($start) le position() and
       position() lt round($start) + round($length)]</eg>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
filter(
  $input,
  if (empty($length)) then (
    fn($item, $pos) { round($start) le $pos }
  ) else (
    fn($item, $pos) { round($start) le $pos and $pos lt round($start) + round($length) }
  )
)
      </fos:equivalent>
      <fos:notes>
         <p>The first item of a sequence is located at position 1, not position 0.</p>
         <p>If <code>$input</code> is the empty sequence, the empty sequence is returned.</p>

         <p>In the two-argument case, the function returns a sequence comprising those items of 
            <code>$input</code> whose 1-based position  
            is greater than or equal to <code>$start</code> (rounded to an integer). 
            No error occurs if <code>$start</code> is zero or negative.</p>

         <p>In the three-argument case, The function returns a sequence comprising those items of 
            <code>$input</code> whose 1-based position  
            is greater than or equal to <code>$start</code> (rounded to an integer), and 
            less than the sum of <code>$start</code> and <code>$length</code> (both rounded to integers). 
            No error occurs if <code>$start</code> is zero or negative, or if <code>$start</code> 
            plus <code>$length</code> exceeds the number of items in the sequence, or if 
            <code>$length</code> is negative.</p>


         <p>As a consequence of the general rules, if <code>$start</code> is
               <code>-INF</code> and <code>$length</code> is <code>+INF</code>, then
               <code>fn:round($start) + fn:round($length)</code> is <code>NaN</code>; since
               <code>position() lt NaN</code> always returns <code>false</code>, the result is the empty sequence.</p>

         <p>The reason the function accepts arguments of type <code>xs:double</code> is that many
            computations on untyped data return an <code>xs:double</code> result; and the reason for
            the rounding rules is to compensate for any imprecision in these floating-point
            computations.</p>
      </fos:notes>

      <fos:examples>
         <fos:variable name="seq" id="v-reverse-seq"
            select="(&quot;item1&quot;, &quot;item2&quot;, &quot;item3&quot;, &quot;item4&quot;, &quot;item5&quot;)"/>
         <fos:example>
            <fos:test use="v-reverse-seq">
               <fos:expression>subsequence($seq, 4)</fos:expression>
               <fos:result>"item4", "item5"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-reverse-seq">
               <fos:expression>subsequence($seq, 3, 2)</fos:expression>
               <fos:result>"item3", "item4"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="895" PR="901" date="2023-12-16">
            <p>The optional third argument can now be supplied as the empty sequence.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="subsequence-where" prefix="fn">
      <fos:signatures>
         <fos:proto name="subsequence-where" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="from" type="(fn(item(), xs:integer) as xs:boolean?)?" default="true#0" note="default-on-empty"/>
            <fos:arg name="to" type="(fn(item(), xs:integer) as xs:boolean?)?" default="false#0" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a contiguous sequence of items from <code>$input</code>, with the start and end
         points located by applying predicates.</p>
      </fos:summary>
      <fos:rules>
         
         <p>Informally, the function returns the subsequence of <code>$input</code> starting with the
         first item that matches the <code>$from</code> predicate, and ending with the first subsequent
         item that matches the <code>$to</code> predicate. If <code>$from</code> is <code>true#0</code>,
         it matches for the first item; if <code>$to</code> is <code>false#0</code>, it accepts all
         remaining items. If <code>$from</code> does not match any items in <code>$input</code>,
         the result is the empty sequence; if <code>$to</code> does not match any items, all items up
         to the last are included in the result.</p>
         
 
 
         
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
let $start := index-where($input, $from)[1] otherwise count($input) + 1
let $end   := index-where($input, $to)[. ge $start][1] otherwise count($input) + 1
return slice($input, $start, $end)
      </fos:equivalent>
      <fos:notes>
         <p>The result includes both the item that matches the <code>$from</code> condition
         and the item that matches the <code>$to</code> condition. To select a subsequence that
         starts after the <code>$from</code> item, apply the <function>fn:tail</function> function 
         to the result. To select a subsequence that ends before the <code>$to</code> item,
         apply the <function>fn:trunk</function> function to the result.</p>
         
         <p>The predicate functions supplied to the <code>$from</code> and <code>$to</code>
         parameters can include an integer position argument as well as the item itself.
         This position will always be 1-based, relative to the start of <code>$input</code>.
         This means it is possible to select items based on their absolute position in the
         <code>$input</code> sequence, but there is no mechanism to select an end position
         relative to the start position. If this is needed, the function can be combined with others:
         for example, to select a subsequence of four items starting with <code>"Barbara"</code>,
         use <code>$input => subsequence-where(fn { . eq "Barbara" }) => slice(end := 4)</code>.</p>
         
         <p>If the requirement is to select all elements stopping before the first <code>h2</code>
            element if it exists, or up to the end of the sequence otherwise, the simplest
         solution is perhaps to write:</p> 
            <eg>slice($input, end:=index-where($input, fn { boolean(self::h2) })[1])</eg>
         
         <p>A return value of <code>()</code> from the <code>$from</code> or <code>$to</code>
         predicate is treated as <code>false</code>.</p>
      </fos:notes>

      
      <fos:examples role="wide">
         <fos:variable name="names" id="v-subseq-seq"><![CDATA[("Anna", "Barbara", "Catherine", "Delia",  "Eliza", "Freda",
  "Gertrude", "Hilda")]]></fos:variable>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression>subsequence-where($names, starts-with(?, "E"))</fos:expression>
               <fos:result>"Eliza", "Freda", "Gertrude", "Hilda"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression>subsequence-where($names, to := starts-with(?, "D"))</fos:expression>
               <fos:result>"Anna", "Barbara", "Catherine", "Delia"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression>subsequence-where($names, to := starts-with(?, "D")) => trunk()</fos:expression>
               <fos:result>"Anna", "Barbara", "Catherine"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression>subsequence-where($names, starts-with(?, "E"), starts-with(?, "G"))</fos:expression>
               <fos:result>"Eliza", "Freda", "Gertrude"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression><eg>subsequence-where(
  $names,
  starts-with(?, "D"), fn { string-length(.) gt 5 }
)</eg></fos:expression>
               <fos:result>"Delia", "Eliza", "Freda", "Gertrude"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression>subsequence-where($names, starts-with(?, "M"))</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression>subsequence-where($names, starts-with(?, "G"), starts-with(?, "Z"))</fos:expression>
               <fos:result>"Gertrude", "Hilda"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression>subsequence-where($names)</fos:expression>
               <fos:result>"Anna", "Barbara", "Catherine", "Delia", "Eliza", "Freda",
  "Gertrude", "Hilda"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression><eg>subsequence-where(
  $names,
  fn($it, $pos) { ends-with($it, "a") and $pos gt 5 }
)</eg></fos:expression>
               <fos:result>"Freda", "Gertrude", "Hilda"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-subseq-seq">
               <fos:expression><eg>subsequence-where(
  $names, 
  to := fn($it, $pos) { ends-with($it, "a") and $pos ge 5 }
)</eg></fos:expression>
               <fos:result>"Anna", "Barbara", "Catherine", "Delia", "Eliza"</fos:result>
            </fos:test>
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="878" PR="940" date="2024-02-05"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   
   <fos:function name="items-at" prefix="fn">
      <fos:signatures>
         <fos:proto name="items-at" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="at" type="xs:integer*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence containing the items from <code>$input</code>
            at positions defined by <code>$at</code>, in the order specified. </p>
      </fos:summary>
      <fos:rules>
         <p>Returns the items in <code>$input</code> at the positions listed
         in <code>$at</code>, in order of the integers in the <code>$at</code> argument.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
for-each($at, fn($index) { subsequence($input, $index, 1) })  
      </fos:equivalent>
      <fos:notes>
         <p>In the simplest case where <code>$at</code> is a single integer,
         <code>fn:items-at($input, 3)</code> returns the same result as <code>$input[3]</code>.</p>
         <p>Compared with a simple positional filter expression, the function is useful because:</p>
         <olist>
            <item><p>It can select items at multiple positions, and unlike <function>fn:subsequence</function>,
            these do not need to be contiguous.</p></item>
            <item><p>The <code>$at</code> expression can depend on the focus.</p></item>
            <item><p>The order of the returned items can differ from their order in the <code>$input</code> sequence.</p></item>
         </olist>
         <p>If any integer in <code>$at</code> is outside the range <code>1 to count($input)</code>, that integer
         is effectively ignored: no error occurs.</p>
         <p>If either of the arguments is the empty sequence, the result is the empty sequence.</p>
         <p>If <code>$at</code> contains duplicate integers, the result also contains duplicates. No de-duplication 
            occurs. If the input sequence contains nodes, these are not copied: instead, the result
            sequence contains multiple references to the same node.</p>
      </fos:notes>
      
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>items-at(11 to 20, 4)</fos:expression>
               <fos:result>14</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>items-at(11 to 20, 4 to 6)</fos:expression>
               <fos:result>14, 15, 16</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>items-at(11 to 20, (7, 3))</fos:expression>
               <fos:result>17, 13</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>items-at(11 to 20, index-of(("a", "b", "c"), "b"))</fos:expression>
               <fos:result>12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>items-at(characters("quintessential"), (4, 8, 3))</fos:expression>
               <fos:result>"n", "s", "i"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>items-at(characters("quintessential"), (4, 8, 1, 1))</fos:expression>
               <fos:result>"n", "s", "q", "q"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>items-at((), 832)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>items-at((), ())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>           
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="213" PR="419" date="2022-11-22"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="slice" prefix="fn">
      <fos:signatures>
         <fos:proto name="slice" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="start" type="xs:integer?" default="0" note="default-on-empty"/>
            <fos:arg name="end" type="xs:integer?" default="0" note="default-on-empty"/>
            <fos:arg name="step" type="xs:integer?" default="0" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence containing selected items from a supplied input sequence based on their position.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Let <code>$S</code> be the first of the following that applies:</p>
         <ulist>
            <item><p>If <code>$start</code> is zero, then 1.</p></item>
            <item><p>If <code>$start</code> is negative, then <code>fn:count($input) + $start + 1</code>.</p></item>
            <item><p>Otherwise, <code>$start</code>.</p></item>
         </ulist>
         <p>Let <code>$E</code> be the first of the following that applies:</p>
         <ulist>
            <item><p>If <code>$end</code> is zero, then <code>fn:count($input)</code>.</p></item>
            <item><p>If <code>$end</code> is negative, then <code>fn:count($input) + $end + 1</code>.</p></item>
            <item><p>Otherwise, <code>$end</code>.</p></item>
         </ulist>
         <p>Let <code>$STEP</code> be the first of the following that applies:</p>
         <ulist>
            <item><p>If <code>$step</code> is zero, then:</p>
            <ulist>
               <item><p>If <code>$E ge $S</code>, then +1</p></item>
               <item><p>Otherwise -1</p></item>
            </ulist>
            </item>
            <item><p>Otherwise, <code>$step</code>.</p></item>
         </ulist>
         <p>If <code>$STEP</code> is negative, the function returns 
            <code>$input => fn:reverse() => fn:slice(-$S, -$E, -$STEP)</code>.</p>
         <!-- So slice((a,b,c,d,e,f), 5, 3, -1) ==> slice(reverse(f,e,d,c,b,a), -5, -3, 1) ==> (e,d,c) --> 
         <p>Otherwise the function returns the result of the expression:</p>
         <eg>$input[position() ge $S and position() le $E and (position() - $S) mod $STEP eq 0]</eg>
         <ednote><edtext>TBA: define formal equivalent.</edtext></ednote>
      </fos:rules>
      <fos:notes>
         <p>The function is inspired by the slice operators in Javascript and Python, but it differs
         in detail to accommodate the tradition of 1-based addressing in XPath. The end position is
         inclusive rather than exclusive, so that in the simple case where <code>$start</code> and
            <code>$end</code> are positive and <code>$end > $start</code>, 
            <code>fn:slice($in, $start, $end)</code>
         returns the same result as <code>$in[position() = $start to $end]</code>.</p>
         <p>This function can be used to enhance the <code>RangeExpression</code>, defined
            in <xspecref spec="XP40" ref="id-range-expressions"/>, to construct a sequence
            of integers based on steps other than 1.</p>        
      </fos:notes>
      
      <fos:examples>
         <fos:variable name="in" id="v-slice" as="xs:string*" select="('a', 'b', 'c', 'd', 'e')"/>
         <fos:example>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 2, end := 4)</fos:expression>
               <fos:result>"b", "c", "d"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 2)</fos:expression>
               <fos:result>"b", "c", "d", "e"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, end := 2)</fos:expression>
               <fos:result>"a", "b"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 3, end := 3)</fos:expression>
               <fos:result>"c"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 4, end := 3)</fos:expression>
               <fos:result>"d", "c"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 2, end := 5, step := 2)</fos:expression>
               <fos:result>"b", "d"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 5, end := 2, step := -2)</fos:expression>
               <fos:result>"e", "c"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 2, end := 5, step := -2)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 5, end := 2, step := 2)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in)</fos:expression>
               <fos:result>"a", "b", "c", "d", "e"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := -1)</fos:expression>
               <fos:result>"e"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := -3)</fos:expression>
               <fos:result>"c", "d", "e"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, end := -2)</fos:expression>
               <fos:result>"a", "b", "c", "d"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := 2, end := -2)</fos:expression>
               <fos:result>"b", "c", "d"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := -2, end := 2)</fos:expression>
               <fos:result>"d", "c", "b"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := -4, end := -2)</fos:expression>
               <fos:result>"b", "c", "d"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := -2, end := -4)</fos:expression>
               <fos:result>"d", "c", "b"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := -4, end := -2, step := 2)</fos:expression>
               <fos:result>"b", "d"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice($in, start := -2, end := -4, step := -2)</fos:expression>
               <fos:result>"d", "b"</fos:result>
            </fos:test>
            <fos:test use="v-slice">
               <fos:expression>slice(("a", "b", "c", "d"), 0)</fos:expression>
               <fos:result>"a", "b", "c", "d"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>slice((1 to 5), step := 2)</fos:expression>
               <fos:result>1, 3, 5</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="starts-with-subsequence" prefix="fn">
      <fos:signatures>
         <fos:proto name="starts-with-subsequence" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="subsequence" type="item()*" usage="transmission"/>
            <fos:arg name="compare" type="(fn(item(), item()) as xs:boolean?)?" default="fn:deep-equal#2" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Determines whether one sequence starts with another, using a supplied callback function to compare items.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function returns <code>true</code> if <code>$input</code> starts with <code>$subsequence</code>,
         when items are compared using the <code>$compare</code> function.</p>
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
count($input) ge count($subsequence) and
every(for-each-pair($input, $subsequence, $compare))        
      </fos:equivalent>
      <fos:notes>
         <p>There is no requirement that the <code>$compare</code> function should have the traditional qualities
            of equality comparison. The result is well-defined, for example, even if <code>$compare</code> is not transitive
         or not symmetric. A return value of <code>()</code> from the function is treated as <code>false</code>.</p>
      </fos:notes>

      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>starts-with-subsequence((), ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>    
            <fos:test>
               <fos:expression>starts-with-subsequence(1 to 10, 1 to 5)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>starts-with-subsequence(1 to 10, ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>starts-with-subsequence(1 to 10, 1 to 10)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>starts-with-subsequence(1 to 10, 1)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>starts-with-subsequence(
  1 to 10,
  101 to 105,
  fn($x, $y) { $x mod 100 = $y mod 100 }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>starts-with-subsequence(
  ("A", "B", "C"),
  ("a", "b"),
  fn($x, $y) {
    compare(
      $x,
      $y,
      "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
    ) eq 0
  }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[let $p := parse-xml("<doc><chap><p/><p/></chap></doc>")//p[2]
return starts-with-subsequence(
  $p/ancestor::*[1],
  $p/parent::*,
  op("is")
)]]></eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>       
            <fos:test>
               <fos:expression>starts-with-subsequence(10 to 20, 1 to 5, op("gt"))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>starts-with-subsequence(
  ("Alpha", "Beta", "Gamma"),
  ("A", "B"),
  starts-with#2
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>starts-with-subsequence(
  ("Alpha", "Beta", "Gamma", "Delta"),
  1 to 3,
  fn($x, $y) { ends-with($x, 'a' ) }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>True because the first three items in the input sequence end with <code>"a"</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="92" PR="222" date="2022-11-01"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="ends-with-subsequence" prefix="fn">
      <fos:signatures>
         <fos:proto name="ends-with-subsequence" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="subsequence" type="item()*" usage="transmission"/>
            <fos:arg name="compare" type="(fn(item(), item()) as xs:boolean?)?" default="fn:deep-equal#2" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Determines whether one sequence ends with another, using a supplied callback function to compare items.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function returns <code>true</code> if <code>$input</code> ends with <code>$subsequence</code>,
            when items are compared using the <code>$compare</code> function.</p>
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
starts-with-subsequence(reverse($input), reverse($subsequence), $compare)     
      </fos:equivalent>
      <fos:notes>
         <p>There is no requirement that the <code>$compare</code> function should have the traditional qualities
            of equality comparison. The result is well-defined, for example, even if <code>$compare</code> is not transitive
            or not symmetric.</p>
         <p>A return value of <code>()</code> from the function is treated as <code>false</code>.</p>
      </fos:notes>
      
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>ends-with-subsequence((), ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>    
            <fos:test>
               <fos:expression>ends-with-subsequence(1 to 10, 5 to 10)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>ends-with-subsequence(1 to 10, ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>ends-with-subsequence(1 to 10, 1 to 10)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>ends-with-subsequence(1 to 10, 10)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>ends-with-subsequence(
  1 to 10,
  108 to 110,
  fn($x, $y) { $x mod 100 = $y mod 100 }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>ends-with-subsequence(
  ("A", "B", "C"),
  ("b", "c"),
  fn($x, $y) {
    compare(
      $x,
      $y,
      "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
    ) eq 0
  }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[let $p := parse-xml("<doc><chap><p/><p/></chap></doc>")//p[2]
return ends-with-subsequence(
  $p/ancestor::node()[last()],
  $p/root(),
  op("is")
)]]></eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>       
            <fos:test>
               <fos:expression>ends-with-subsequence(10 to 20, 1 to 5, op("gt"))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>ends-with-subsequence(
  ("Alpha", "Beta", "Gamma"),
  ("B", "G"),
  starts-with#2
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>ends-with-subsequence(
  ("Alpha", "Beta", "Gamma", "Delta"),
  1 to 2,
  fn($x, $y) { string-length($x) eq 5 }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>True because the last two items in the input sequence have a string length of 5.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="92" PR="222" date="2022-11-01"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="contains-subsequence" prefix="fn">
      <fos:signatures>
         <fos:proto name="contains-subsequence" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="transmission"/>
            <fos:arg name="subsequence" type="item()*" usage="transmission"/>
            <fos:arg name="compare" type="(fn(item(), item()) as xs:boolean?)?" default="fn:deep-equal#2" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Determines whether one sequence contains another as a contiguous subsequence, using a supplied callback function to compare items.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function returns <code>true</code> if <code>$input</code> contains a consecutive subsequence matching <code>$subsequence</code>,
            when items are compared using the <code>$compare</code> function.</p>
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
some $i in 0 to count($input) - count($subsequence)
satisfies (
  every $j in 1 to count($subsequence)
  satisfies $compare($input[$i + $j], $subsequence[$j])   
)
      </fos:equivalent>
      <fos:notes>
         <p>There is no requirement that the <code>$compare</code> function should have the traditional qualities
            of equality comparison. The result is well-defined, for example, even if <code>$compare</code> is not transitive
            or not symmetric.</p>
         <p>A return value of <code>()</code> from the function is treated as <code>false</code>.</p>
      </fos:notes>
      
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>contains-subsequence((), ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>    
            <fos:test>
               <fos:expression>contains-subsequence(1 to 10, 3 to 6)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>contains-subsequence(1 to 10, (2, 4, 6))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>contains-subsequence(1 to 10, ())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>contains-subsequence(1 to 10, 1 to 10)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>contains-subsequence(1 to 10, 5)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>contains-subsequence(
  1 to 10,
  103 to 105,
  fn($x, $y) { $x mod 100 = $y mod 100 }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>contains-subsequence(
  ("A", "B", "C", "D"),
  ("b", "c"),
  fn($x, $y) {
    compare(
      $x,
      $y,
      "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
    ) eq 0
  }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[let $chap := parse-xml("<doc><chap><h1/><p/><p/><footnote/></chap></doc>")//chap
return contains-subsequence(
  $chap ! child::*,
  $chap ! child::p,
  op("is")
)]]></eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>True because the <code>p</code> children of the <code>chap</code> element form a contiguous subsequence.</fos:postamble>
            </fos:test>       
            <fos:test>
               <fos:expression>contains-subsequence(10 to 20, (5, 3, 1), op("gt"))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>contains-subsequence(
  ("Alpha", "Beta", "Gamma", "Delta"), ("B", "G"),
  starts-with#2
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>contains-subsequence(
  ("Zero", "Alpha", "Beta", "Gamma", "Delta", "Epsilon"),
  1 to 4,
  fn($x, $y) { ends-with($x, 'a') }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>True because there is a run of 4 consecutive items ending in <code>"a"</code>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="92" PR="222" date="2022-11-01"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="unordered" prefix="fn">
      <fos:signatures>
         <fos:proto name="unordered" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic-wrt-ordering</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the items of <code>$input</code> in an <termref
               def="implementation-dependent">implementation-dependent</termref> order.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the items of <code>$input</code> in an <termref
               def="implementation-dependent">implementation-dependent</termref> order.</p>
      </fos:rules>
      <fos:notes>
         <p>Query optimizers may be able to do a better job if the order of the output sequence is
            not specified. For example, when retrieving prices from a purchase order, if an index
            exists on prices, it may be more efficient to return the prices in index order rather
            than in document order.</p>
         <p>This function does not guarantee that the resulting sequence will be in an order
            different from the input sequence. Many times the two sequences will be identical. </p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>unordered((1, 2, 3, 4, 5))</fos:expression>
               <fos:result allow-permutation="true">(1, 2, 3, 4, 5)</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="void" prefix="fn">
      <fos:signatures>
         <fos:proto name="void" return-type="empty-sequence()">
            <fos:arg name="input" type="item()*" default="()" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Absorbs the argument.</p>
      </fos:summary>
      <fos:rules>
         <p>The function absorbs the supplied <code>$input</code> argument and
            returns the empty sequence.</p>
      </fos:rules>
      <fos:notes>
         <p>The function can be used to discard unneeded output of expressions
            (functions, third-party libraries, etc.).</p>
         <p>It can also be used to discard results during development.</p>
         <!--<p>The function is utilized by built-in functions such as <function>map:get</function>
            to return the empty sequence for arbitrary input.</p>-->
         <p>It is <termref def="implementation-dependent">implementation-dependent</termref>
            whether the supplied argument is evaluated or ignored. An implementation may decide to
            evaluate <termref def="dt-nondeterministic">nondeterministic</termref> expressions and
            ignore deterministic ones.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>void(1 to 1000000)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <!--<fos:test>
               <fos:expression>array:get(array { 1, 2, 3 }, 4, void#1)</fos:expression>
               <fos:result>()</fos:result>
               <fos:postamble>Without the third argument, an error would be raised.</fos:postamble>
            </fos:test>-->
            <fos:test>
               <fos:expression>for $f in (identity#1, void#1) return $f(123)</fos:expression>
               <fos:result>123</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>let $mapping := () 
return for-each(1 to 10, $mapping otherwise void#0)</eg></fos:expression>
               <fos:result>()</fos:result>
               <fos:postamble>Indicates that if no mapping is supplied, all items are dropped.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1029" PR="1032" date="2025-02-25"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="zero-or-one" prefix="fn">
      <fos:signatures>
         <fos:proto name="zero-or-one" return-type="item()?">
            <fos:arg name="input" type="item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>input</code> if it contains zero or one items. Otherwise, raises an
            error.</p>
      </fos:summary>
      <fos:rules>
         <p>Except in error cases, the function returns <code>$input</code> unchanged.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false">
if (count($input) le 1) 
then $input 
else error(#Q{http://www.w3.org/2005/xqt-errors}FORG0003))
      </fos:equivalent>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RG" code="0003"
            /> if <code>$input</code>
            contains more than one item.</p>
      </fos:errors>
   </fos:function>

   <fos:function name="one-or-more" prefix="fn">
      <fos:signatures>
         <fos:proto name="one-or-more" return-type="item()+">
            <fos:arg name="input" type="item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>$input</code> if it contains one or more items. Otherwise, raises an error.
         </p>
      </fos:summary>
      <fos:rules>
         <p>Except in error cases, the function returns <code>$input</code> unchanged.</p>

      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false">
if (count($input) ge 1) 
then $input 
else error(#Q{http://www.w3.org/2005/xqt-errors}FORG0004))
      </fos:equivalent>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RG" code="0004"
         /> if <code>$input</code> is an
            empty sequence.</p>
      </fos:errors>
   </fos:function>
   <fos:function name="exactly-one" prefix="fn">
      <fos:signatures>
         <fos:proto name="exactly-one" return-type="item()">
            <fos:arg name="input" type="item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>$input</code> if it contains exactly one item. Otherwise, raises an error.
         </p>
      </fos:summary>
      <fos:rules>
         <p>Except in error cases, the function returns <code>$input</code> unchanged.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false">
if (count($input) eq 1) 
then $input 
else error(#Q{http://www.w3.org/2005/xqt-errors}FORG0005))
      </fos:equivalent>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="RG" code="0005"
         /> if <code>$input</code> is an
            empty sequence or a sequence containing more than one item.</p>
      </fos:errors>
   </fos:function>
   <fos:function name="deep-equal" prefix="fn">
      <fos:signatures>
         <fos:proto name="deep-equal" return-type="xs:boolean">
            <fos:arg name="input1" type="item()*" usage="absorption"/>
            <fos:arg name="input2" type="item()*" usage="absorption"/>
            <fos:arg name="options" type="(xs:string | map(*))?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p> This function assesses whether two sequences are deep-equal to each other. To be
            deep-equal, they must contain items that are pairwise deep-equal; and for two items to
            be deep-equal, they must either be atomic items that compare equal, or nodes of the
            same kind, with the same name, whose children are deep-equal<phrase>,
               or maps with matching entries, or arrays with matching members.</phrase></p>
      </fos:summary>
      <fos:rules>

         <p>The <code>$options</code> argument defines additional parameters controlling
            how the comparison is done. If it is supplied as a map, then the <termref def="option-parameter-conventions"
               >option parameter conventions</termref> apply.</p>
         <p>For backwards compatibility reasons, the <code>$options</code> argument can also be set
            to a string containing a collation name. Supplying a string <code>$S</code> for this argument is equivalent
            to supplying the map <code>{ 'collation': $S }</code>.</p>
         <p>If the two sequences (<code>$input1</code> and <code>$input2</code>) 
            are both empty, the function returns <code>true</code>.</p>
         <p>If the two sequences are of different lengths, the function returns
            <code>false</code>.</p>
         <p>If the two sequences are of the same length, the comparison is controlled by the 
            <code>ordered</code> option:</p>
         <ulist>
            <item><p>By default, the option is <code>true</code>: The function returns
            <code>true</code> if and only if every item in the sequence <code>$input1</code> is
            deep-equal to the item at the same position in the sequence <code>$input2</code>.
            </p></item>
            <item><p>If the option is set to <code>false</code>, the function returns
            <code>false</code> if and only if every item in the sequence <code>$input1</code>
            is deep-equal to an item at some position in the sequence <code>$input2</code>,
            and vice versa.</p></item>
         </ulist>
         <p>The rules for
            deciding whether two items are deep-equal appear below.</p>
         <p>The entries that may appear in the <code>$options</code> map are as follows. The detailed rules
            for the interpretation of each option appear later.</p>
            
            <fos:options>
               <fos:option key="base-uri">
                  <fos:meaning>Determines whether the <code>base-uri</code> of a node is significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="collation">
                  <fos:meaning>Identifies a collation which is used at all levels
                     of recursion when strings are compared (but not when names are compared), according to
                     the rules in <specref ref="choosing-a-collation"/>. If the argument is not supplied,
                     or if it is empty, then the default collation from the 
                     dynamic context of the caller is used.</fos:meaning>
                  <fos:type>xs:string</fos:type>
                  <fos:default>fn:default-collation()</fos:default>
               </fos:option>
               <fos:option key="comments">
                  <fos:meaning>Determines whether comments are significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="debug">
                  <fos:meaning>Requests diagnostics in the case where the function returns <code>false</code>.
                     When this option is set and the two inputs are found to be not equal, the implementation
                     <rfc2119>should</rfc2119> output messages (in an implementation-dependent format and to
                     an implementation-dependent destination) indicating the nature of the differences that
                     were found.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="id-property">
                  <fos:meaning>Determines whether the <code>id</code> property of elements and attributes is significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="idrefs-property">
                  <fos:meaning>Determines whether the <code>idrefs</code> property of elements and attributes is significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="in-scope-namespaces">
                  <fos:meaning>Determines whether the in-scope namespaces of elements are significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="items-equal">
                  <fos:meaning>A user-supplied function to test whether two items
                     are considered equal. The function can return <code>true</code>
                     or <code>false</code> to indicate that two items are or are not
                     equal, overriding the normal rules that would apply to those items;
                     or it can return the empty sequence, to indicate that the normal
                     rules should be followed. Note that returning <code>()</code>
                     is <emph>not</emph> equivalent to returning <code>false</code>.
                  </fos:meaning>
                  <fos:type>fn(item(), item()) as xs:boolean?</fos:type>
                  <fos:default>fn:void#0</fos:default>
               </fos:option>
               <fos:option key="map-order">
                  <fos:meaning>Determines whether the order of entries in maps is significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="namespace-prefixes">
                  <fos:meaning>Determines whether namespace prefixes in <code>xs:QName</code> values (particularly
                     the names of elements and attributes) are significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="nilled-property">
                  <fos:meaning>Determines whether the <code>nilled</code> property of elements and attributes is significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="normalization-form">
                  <fos:meaning>If present, indicates that text and attributes are converted to the specified
                     Unicode normalization form prior to comparison. The value is as for the corresponding
                     argument of <function>fn:normalize-unicode</function>.
                  </fos:meaning>
                  <fos:type>xs:string?</fos:type>
                  <fos:default>()</fos:default>
               </fos:option>              
               <fos:option key="ordered">
                  <fos:meaning>Controls whether the top-level order of the items of the input sequences
                    is considered.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>true</fos:default>
               </fos:option>
               <fos:option key="processing-instructions">
                  <fos:meaning>Determines whether processing instructions are significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="timezones">
                  <fos:meaning>Determines whether timezones in date/time values are significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="type-annotations">
                  <fos:meaning>Determines whether type annotations are significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>false</fos:default>
               </fos:option>
               <fos:option key="type-variety">
                  <fos:meaning>Determines whether the variety of the type annotation of an element 
                     (whether it has complex content or simple content) is significant.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>true</fos:default>
               </fos:option>
               <fos:option key="typed-values">
                  <fos:meaning>Determines whether nodes are compared using their typed values rather than
                     their string values.
                  </fos:meaning>
                  <fos:type>xs:boolean</fos:type>
                  <fos:default>true</fos:default>
               </fos:option>
               <fos:option key="unordered-elements">
                  <fos:meaning>A list of QNames of elements considered to be unordered: that is, their child
                     elements may appear in any order.
                  </fos:meaning>
                  <fos:type>xs:QName*</fos:type>
                  <fos:default>()</fos:default>
               </fos:option>
               <fos:option key="whitespace">
                  <fos:meaning><phrase diff="chg" at="2023-03-13">Determines the extent to which whitespace 
                     is treated as significant. The value
                     <code>preserve</code> retains all whitespace. The value <code>strip</code> ignores text nodes
                     consisting entirely of whitespace.
                     The value <code>normalize</code> ignores whitespace text nodes in the same way as
                     the <code>strip</code> option, and additionally compares text and attribute nodes after 
                     normalizing whitespace in accordance with the rules of the <function>fn:normalize-space</function> 
                     function. The detailed rules, given below, also take into account type annotations and 
                     <code>xml:space</code> attributes.
                  </phrase>
                  </fos:meaning>
                  <fos:type>enum("preserve", "strip", "normalize")</fos:type>
                  <fos:default>preserve</fos:default>
               </fos:option>
            </fos:options>
         
         <note><p>As a general rule for boolean options (but not invariably), the value <code>true</code> indicates 
            that the comparison is more strict. </p></note>

         <p>In the following rules, where a recursive call on <function>fn:deep-equal</function> is made, this is assumed
         to use the same values of <code>$options</code> as the original call.</p>
         
         <p>The rules reference a function <code>equal-strings</code> which compares two <code>xs:string</code>
            or <code>xs:anyURI</code> values as follows:</p>
         
         <olist>
            <item><p>If the <code>whitespace</code> option is set to <code>normalize</code>, then each string is processed
               by calling the <function>fn:normalize-space</function> function.</p></item>
            <item><p>If the <code>normalization-form</code> option is present, each string is then normalized
            by calling the <function>fn:normalize-unicode</function> function, supplying the specified normalization
            form.</p></item>           
            <item><p>The two strings are then compared for equality under the requested collation.</p></item>
         </olist>
         
         <p>More formally, the <code>equal-strings</code> function is equivalent to the following
            implementation in XQuery:</p>
         <eg><![CDATA[
declare function equal-strings(
  $string1  as xs:string,
  $string2  as xs:string, 
  $options  as map(*)
) as xs:boolean {
  let $n1 := if ($options?normalization-form)
             then normalize-unicode(?, $options?normalization-form) 
             else identity#1
  let $n2 := if ($options?whitespace = "normalize")
             then normalize-space#1 
             else identity#1               
  return compare($n1($n2($string1)), $n1($n2($string2)), $options?collation) eq 0    
}]]></eg>
         <p>The rules for deciding whether two items <code>$i1</code> and <code>$i2</code> are deep-equal
            are as follows.</p>
         
         <p>The two items are first compared using the function supplied in the <code>items-equal</code>
            option. If this returns <code>true</code> then the items are deep-equal. If it returns
            <code>false</code> then the items are not deep-equal. If it returns the empty sequence
            (which is always the case if the option is not explicitly specified)
            then the two items are deep-equal if one or more of the following conditions are true:</p>
         <olist>
            <item>
               <p>All of the following conditions are true:</p>
               <olist>
                  <item>
                     <p><code>$i1</code> is an atomic item.</p></item>
                  <item>
                     <p><code>$i2</code> is an atomic item.</p></item>
                  <item>
                     <p>Either the <code>type-annotations</code> option is <code>false</code>, or both atomic items have
                     the same type annotation.</p>
                  </item>
                  <item>
                     <p>One of the following conditions is true:</p>
                     <olist>
                        <item><p>If both <code>$i1</code> and <code>$i2</code> are instances of
                           <code>xs:string</code>, <code>xs:untypedAtomic</code>, or <code>xs:anyURI</code>,
                           <code>equal-strings($i1, $i2, $collation, $options)</code>
                           returns <code>true</code>.
                        </p></item>

                        <item><p>Otherwise, <code>fn:compare($i1, $i2)</code>
                           returns zero.
                        </p></item>
                     </olist>
                     <p>If <code>$i1</code> and <code>$i2</code> are not comparable, that is,
                        if the expression <code>compare($i1, $i2)</code>  raises an error, then the function
                     returns <code>false</code>; it does not report an error.</p>
                  </item>
                  
                  <item>
                     <p>One of the following conditions is true:</p>
                     <olist>
                        <item><p>Option <code>namespace-prefixes</code> is <code>false</code>.</p></item>
                        <item><p>Neither <code>$i1</code> nor <code>$i2</code> is of type
                        <code>xs:QName</code> or <code>xs:NOTATION</code>.</p></item>
                        <item><p><code>$i1</code> and <code>$i2</code> are qualified names with the same namespace prefix.</p></item>
                     </olist>
                  </item>
                  <item>
                     <p>One of the following conditions is true:</p>
                     <olist>
                        <item><p>Option <code>timezones</code> is <code>false</code>.</p></item>
                        <item><p>Neither <code>$i1</code> nor <code>$i2</code> is of type
                           <code>xs:date</code>, <code>xs:time</code>, <code>xs:dateTime</code>, 
                           <code>xs:gYear</code>, <code>xs:gYearMonth</code>, <code>xs:gMonth</code>, 
                           <code>xs:gMonthDay</code>, or <code>xs:gDay</code>.</p></item>
                        <item><p>Neither <code>$i1</code> nor <code>$i2</code> has a timezone component.</p></item>
                        <item><p>Both <code>$i1</code> and <code>$i2</code> have a timezone component and the
                        timezone components are equal.</p></item>
                     </olist>
                  </item>
               </olist>
            </item>
            <item>
               <p>All of the following conditions are true:</p>
               <olist>
                  <item>
                     <p><code>$i1</code> is a map.</p>
                  </item>
                  <item>
                     <p><code>$i2</code> is a map.</p>
                  </item>
                  <item>
                     <p>Both maps have the same number of entries.</p>
                  </item>
                  <item>
                     <p>For every entry in the first map, there is an entry in the second map that:</p>
                     <olist>
                        <item>
                           <p>has the <termref def="dt-same-key"
                              >same key</termref> (note that the
                              collation is not used when comparing keys), and </p>
                        </item>
                        <item>
                           <p>has the same associated value (compared using the <function>fn:deep-equal</function>
                              function, recursively).</p>
                        </item>
                     </olist>
                  </item>
                  <item>
                     <p>Either <code>map-order</code> is false, or the entries in both maps appear in the same order,
                     that is, the <var>Nth</var> key in the first map is the <termref def="dt-same-key"
                              >same key</termref> as the <var>Nth</var> key in the second map, for all <var>N</var>.</p>
                  </item>
               </olist>
               
             </item>
            <item>
               <p>All the following conditions are true:</p>
               <olist>
                  <item><p><code>$i1</code> is an array.</p></item>
                  <item><p><code>$i2</code> is an array.</p></item>
                  <item>
                     <p>Both arrays have the same number of members (<code>array:size($i1) eq
                           array:size($i2)</code>).</p>
                  </item>
                  <item>
                     <p>Members in the same position of both arrays are deep-equal to each other: that is,
                           <code>every $p in 1 to array:size($i1) satisfies deep-equal($i1($p), $i2($p),
                           $collation, $options).</code></p>
                  </item>
               </olist>
            </item>
            <item diff="add" at="2023-05-25">
               <p>All the following conditions are true:</p>
               <olist>
                  <item><p><code>$i1</code> is a function item and is not a map or array.</p></item>
                  <item><p><code>$i2</code> is a function item and is not a map or array.</p></item>
                  <item><p><code>$i1</code> and <code>$i2</code> have the same function identity.
                     The concept of function identity is explained in <xspecref spec="DM40" ref="function-items"/>.</p></item>                 
               </olist>
            </item>
            <item>
               <p>All the following conditions are true:</p>
               <olist>
                  <item><p><code>$i1</code> is a node (specifically, an XNode).</p></item>
                  <item><p><code>$i2</code> is a node (specifically, an XNode).</p></item>
                  <item><p>Both nodes have the same node kind.</p></item>
                  <item><p>Either the <code>base-uri</code> option is <code>false</code>, or both nodes have the same value
                     for their base URI property, or both nodes have an absent base URI.</p></item>
                  <item><p>Let <code>significant-children($parent)</code> be the sequence of nodes obtained by applying the following
                  steps to the children of <code>$parent</code>, in turn:</p>
                     <olist>
                        <item><p>Comment nodes are discarded if the option <code>comments</code> is <code>false</code>.</p></item>
                        <item><p>Processing instruction nodes are discarded if the option <code>processing-instructions</code> is <code>false</code>.</p></item>
                        <item><p>Adjacent text nodes are merged.</p></item>
                        <item><p>Whitespace-only text nodes are discarded if both the following conditions are true:</p>
                           <olist>
                              <item>
                                    <p>The option <code>whitespace</code> is set to <code>strip</code>
                                       or <code>normalize</code>; and</p>
                              </item>
                              <item><p>The text node is not within the scope
                              of an element that has the attribute <code>xml:space="preserve"</code>.</p></item>
                           </olist>
                           <note><p>Whitespace text nodes will already have been discarded if
                              <code>$parent</code> is a schema-validated element node whose type annotation 
                              is a complex type with an element-only or empty content model.</p></note>
                        </item>
                     </olist>
                  
                  </item>
                  <item>
                     <p>One of the following conditions is true.</p>
                     <olist>
                        <item>
                           <p>Both nodes are document nodes, and the sequence <code>significant-children($i1)</code> 
                              is deep-equal to the sequence <code>significant-children($i2)</code>.</p>
                        </item>
                        <item>
                           <p>Both nodes are element nodes, and all the following conditions are true:</p>
                           <olist>
                              <item>
                                 <p>The two nodes have the same name, that is <code>(node-name($i1) eq
                                    node-name($i2))</code>.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>namespace-prefixes</code> is <code>false</code>, or both element
                                    names have the same prefix.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>in-scope-namespaces</code> is <code>false</code>, or both element
                                    nodes have the same in-scope namespace bindings.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>type-annotations</code> is <code>false</code>, or both
                                    element nodes have the same type annotation.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>id-property</code> is <code>false</code>, or both element
                                    nodes have the same value for their <code>is-id</code> property.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>idrefs-property</code> is <code>false</code>, or both element
                                    nodes have the same value for their <code>is-idrefs</code> property.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>nilled-property</code> is <code>false</code>, or both element
                                    nodes have the same value for their <code>nilled</code> property.</p>
                              </item>
                              <item>
                                 <p>One of the following conditions is true:</p>
                                 <olist>
                                    <item><p>The option <code>type-variety</code> is <code>false</code>.</p></item>
                                    <item><p>Both nodes are annotated as having simple content.
                                       For this purpose <term>simple content</term>
                                       means either a simple type or a complex type with simple content.</p></item>
                                    <item><p>Both nodes are annotated as having complex content. For this purpose 
                                       <term>complex content</term> means a complex type whose variety is mixed, element-only, or
                                       empty.</p></item>
                                 </olist>
                                 <note>
                                    <p>It is a consequence of this rule that, by default, validating a document <var>D</var>
                                       against a schema will usually (but not necessarily) result in a document
                                       that is not deep-equal to <var>D</var>. The exception is when the schema
                                       allows all elements to have mixed content.</p>
                                 </note>
                                 
                              </item>
                              <item>
                                 <p>The two nodes have the same number of attributes, and for every attribute
                                    <code>$a1</code> in <code>$i1/@*</code> there exists an attribute
                                    <code>$a2</code> in <code>$i2/@*</code> such that <code>node-name($a1) eq node-name($a2)</code>
                                    and <code>$a1</code> and <code>$a2</code> are deep-equal.</p>
                                 <note><p>Attributes, like other items, may be compared using the supplied <code>items-equal</code>
                                 function. However, this function will not be called to compare two attribute nodes unless
                                 they have the same name.</p></note>
                              </item>
                              <item>
                                 <p> One of the following conditions holds:</p>
                                 <olist>
                                    <item>
                                       <p>Both element nodes are annotated as having simple content (as defined
                                          above), the <code>typed-values</code> option is <code>true</code>, 
                                          and the typed value of <code>$i1</code> is deep-equal
                                          to the typed value of <code>$i2</code>.</p>
                                       <note><p>The typed value of an element node is used only when the element
                                       has simple content, which means that no error can occur as a result
                                       of atomizing a node with no typed value.</p></note>
                                    </item>
                                    <item>
                                       <p>Both element nodes are annotated as having simple content (as defined
                                          above), the <code>typed-values</code> option is <code>false</code>, 
                                          and the <code>equal-strings</code> function returns <code>true</code> when
                                          applied to the string value of <code>$i1</code> 
                                          and the string value of <code>$i2</code>.</p>
                                    </item>
                                    <item>
                                       <p>Both element nodes have a type annotation that is a complex type with
                                          element-only, mixed, or empty content,
                                          the (common) element name is not present in the <code>unordered-elements</code> option,
                                          and the sequence <code>significant-children($i1)</code> is
                                          deep-equal to the sequence <code>significant-children($i2)</code>.</p>
                                    </item>
                                    <item>
                                       <p>Both element nodes have a type annotation that is a complex type with
                                          element-only, mixed, or empty content,
                                          the (common) element name is present in the <code>unordered-elements</code> option,
                                          and the sequence <code>significant-children($i1)</code> is
                                          deep-equal to some permutation of the sequence <code>significant-children($i2)</code>.</p>
                                       <note>
                                          <p>Elements annotated as <code>xs:untyped</code> fall into this category.</p>
                                          <p>Including an element name in the <code>unordered-elements</code> list is unlikely
                                          to be useful except when the relevant elements have element-only content, but
                                          this is not a requirement: the rules apply equally to elements with mixed content,
                                          or even (trivially) to elements with empty content.</p>
                                       </note>
                                    </item>
                                 </olist>
                              </item>
                           </olist>
                        </item>
  
                        <item>
                           <p>Both nodes are attribute nodes, and all the following conditions are true:</p>
                           <olist>
      
                              <item>
                                 <p>The two attribute nodes have the same name, that is <code>(node-name($i1) eq
                                       node-name($i2))</code>.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>namespace-prefixes</code> is <code>false</code>, or both
                                 attribute names have the same prefix.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>type-annotations</code> is <code>false</code>, or both
                                 attribute nodes have the same type annotation.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>id-property</code> is <code>false</code>, or both attribute nodes
                                    have the same value for their <code>is-id</code> property.</p>
                              </item>
                              <item>
                                 <p>Either the option <code>idrefs-property</code> is <code>false</code>, or both attribute nodes
                                    have the same value for their <code>is-idrefs</code> property.</p>
                              </item>
                              <item>
                                 <p>Let <var>T</var> be true if the option <code>typed-value</code> is true
                                    and both attributes <code>$i1</code> and <code>$i2</code> have a type
                                 annotation other than <code>xs:untypedAtomic</code>.</p>
                                 <p>Then either <var>T</var> is true and the typed value of <code>$i1</code> 
                                    is deep-equal to the typed value of <code>$i2</code>, or <var>T</var> is false 
                                    and the <code>equal-strings</code> function returns true when applied to the 
                                    string value of <code>$i1</code> and the string value of <code>$i2</code>. </p>
                              </item>
                              
                              
                           </olist>
                        </item>

                        <item>
                           <p>Both nodes are processing instruction nodes, and all the following conditions are true:</p>
                              <olist>
                                 <item>
                                    <p>The two nodes have the same name, that is <code>(node-name($i1) eq
                                          node-name($i2))</code>.</p>
                                 </item>
                                 <item>
                                    <p>The <code>equal-strings</code> function returns <code>true</code> when applied to 
                                       the string value of <code>$i1</code> 
                                       and the string value of <code>$i2</code>.</p>
                                 </item>
                              </olist>
                        </item>
                        <item>
                           <p>Both nodes are namespace nodes, and all the following conditions are true:</p>
                           <olist>
                              <item>
                                 <p>The two nodes either have the same name or are both nameless, that is
                                    <code>fn:deep-equal(node-name($i1), node-name($i2))</code>.</p>
                              </item>
                              <item>
                                 <p>The string value of <code>$i1</code> is equal to the string value of
                                    <code>$i2</code> when compared using the Unicode codepoint collation.</p>
                              </item>
                           </olist>
                           <note><p>Namespace nodes are not considered directly unless they appear in the top-level sequences
                           passed explicitly to the <function>fn:deep-equal</function> function.</p></note>
                        </item>
                        <item>
                           <p>Both nodes are comment nodes, and the <code>equal-strings</code> function 
                              returns <code>true</code> when applied to their string values.</p>
                        </item>
                        <item>
                           <p>Both nodes are text nodes, and the <code>equal-strings</code> function 
                              returns <code>true</code> when applied to their string values.</p>
                          
                        </item>
                  </olist>
                  </item>
                  </olist>
            </item>
            <item>
               <p>All the following conditions are true:</p>
               <olist>
                  <item><p><code>$i1</code> is a JNode.</p></item>
                  <item><p><code>$i2</code> is a JNode.</p></item>
                  <item><p>The <term>·jvalue·</term> property of <code>$i1</code>
                  is deep-equal to the <term>·jvalue·</term> property of <code>$i2</code>.</p>
                  <note><p>The other properties of the two JNodes, such as <term>·jparent·</term>
                  and <term>·jkey·</term>, are ignored. As with XNodes, deep equality
                  considers only the subtree rooted at the node, and not its position within
                  a containing tree.</p></note>
                  </item>
               </olist>
            </item>
                  
               
            
          </olist>
         <p>In all other cases the result is <code>false</code>.</p>
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <xerrorref spec="XP" class="TY"
            code="0004" type="type"/> if the value of 
            <code>$options</code> includes an entry whose key is defined 
            in this specification, and whose value is not of the permitted type for that key.</p>
         <p>A dynamic error is raised <errorref spec="FO" class="JS" code="0005"
         /> if the value of 
            <code>$options</code> includes an entry whose key is defined 
            in this specification, and whose value is not a permitted value for that key.</p>
      </fos:errors>
      <fos:notes>
         <p>By default, whitespace in text nodes and attributes is considered significant. There are various ways
         whitespace differences can be ignored:</p>
         <ulist>
            <item><p>If nodes have been schema-validated, setting the <code>typed-values</code> 
               option to true causes the typed values rather
               than the string values to be compared. This will typically cause whitespace to be ignored
               except where the type of the value is <code>xs:string</code>.</p></item>
            <item><p>Setting the <code>whitespace</code> option to <code>normalize</code> causes all
            text and attribute nodes to have leading and trailing whitespace removed, and intermediate
            whitespace reduced to a single character.</p></item>
         </ulist>
         <p>By default, two nodes are not required to have the same type annotation, and they are not
            required to have the same in-scope namespaces. They may also differ in their parent,
            their base URI, and the values returned by the <code>is-id</code> and
               <code>is-idrefs</code> accessors (see <xspecref
               spec="DM40" ref="dm-is-id"/> and
               <xspecref spec="DM40"
               ref="dm-is-idrefs"
            />). The order of children is significant,
            but the order of attributes is insignificant. </p>
         <p>By default, the contents of comments and processing instructions are significant only if these nodes
            appear directly as items in the two sequences being compared. The content of a comment
            or processing instruction that appears as a descendant of an item in one of the
            sequences being compared does not affect the result. <phrase diff="chg" at="issue930">In previous versions
            of this specification, the presence of a comment
            or processing instruction, if it caused text to be split across two text nodes, might
            affect the result; this has been changed in 4.0 so that adjacent text nodes are merged
            after comments and processing instructions have been stripped.</phrase></p>
         <p>Comparing items of different kind (for example, comparing an atomic
            item to a node, or a map to an array, or an integer to an <code>xs:date</code>) returns <code>false</code>, 
            it does not return an error. So
            the result of <code>fn:deep-equal(1, current-dateTime())</code> is <code>false</code>.</p>
         
         <p>The <code>items-equal</code> callback function may be used to override the default rules
         for comparing individual items. For example, it might return <code>true</code> unconditionally
         when comparing two <code>@timestamp</code> attributes, if there is no expectation that the
         two trees will have identical timestamps. Given two nodes <code>$n1</code> and <code>$n2</code>, 
            it might compare them using the <code>is</code> operator, so that instead of comparing the
         descendants of the two nodes, the function simply checks whether they are the same node.
         Given two function items <code>$f1</code> and <code>$f2</code> it might return true unconditionally,
         knowing that there is no effective way to test if the functions are equivalent. Given
         two numeric values, it might return <code>true</code> if they are equal to six decimal places.</p>
         
         <p>It is good practice for the <code>items-equal</code> callback function to be reflexive,
         symmetric, and transitive; if it is not, then the <function>fn:deep-equal</function> function itself
         will lack these qualities. <emph>Reflexive</emph> means that every item (including <code>NaN</code>)
         should be equal to itself; <emph>symmetric</emph> means that <code>items-equal(A, B)</code>
         should return the same result as <code>items-equal(B, A)</code>, and <emph>transitive</emph>
            means that <code>items-equal(A, B)</code> and <code>items-equal(B, C)</code> should
            imply <code>items-equal(A, C)</code>.</p>
         
         <p>Setting the <code>ordered</code> option to <code>false</code> or supplying the
            <code>unordered-elements</code> option may result in poor performance when comparing
            long sequences, especially if the <code>items-equal</code> callback function is supplied.</p>
         
      </fos:notes>
      <fos:examples>
         <fos:variable name="at" id="v-deep-equal-at" as="element()"><![CDATA[<attendees>
  <name last="Parker" first="Peter"/>
  <name last="Barker" first="Bob"/>
  <name last="Parker" first="Peter"/>
</attendees>]]></fos:variable>
         <fos:example>
            <fos:test use="v-deep-equal-at" spec="XQuery">
               <fos:expression>deep-equal($at, $at/*)</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-deep-equal-at" spec="XQuery">
               <fos:expression>deep-equal($at/name[1], $at/name[2])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-deep-equal-at" spec="XQuery">
               <fos:expression>deep-equal($at/name[1], $at/name[3])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-deep-equal-at" spec="XQuery">
               <fos:expression>deep-equal($at/name[1], 'Peter Parker')</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-deep-equal-at" spec="XQuery">
               <fos:expression><eg>deep-equal(
  $at//name[@first="Bob"], 
  $at//name[@last="Barker"],
  options := { 'items-equal': op('is') } 
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>Tests whether the two input sequences contain exactly the same nodes.</fos:postamble>
            </fos:test>           
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>deep-equal([ 1, 2, 3], [ 1, 2, 3 ])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>deep-equal((1, 2, 3), [ 1, 2, 3 ])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>deep-equal(
  { 1: 'a', 2: 'b' },
  { 2: 'b', 1: 'a' }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>deep-equal(
  (1, 2, 3, 4),
  (1, 4, 3, 2),
  options := { 'ordered': false() }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>deep-equal(
  (1, 1, 2, 3),
  (1, 2, 3, 3),
  options := { 'ordered': false() }
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[deep-equal(
  parse-xml("<a xmlns='AA'/>"),
  parse-xml("<p:a xmlns:p='AA'/>")
)]]></eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>By default, namespace prefixes are ignored</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[deep-equal(
  parse-xml("<a xmlns='AA'/>"),
  parse-xml("<p:a xmlns:p='AA'/>"),
  options := { 'namespace-prefixes': true() }
)]]></eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>False because the namespace prefixes differ</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[deep-equal(
  parse-xml("<a xmlns='AA'/>"),
  parse-xml("<p:a xmlns:p='AA'/>"),
  options := { 'in-scope-namespaces': true() }
)]]></eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>False because the in-scope namespace bindings differ</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[deep-equal(
  parse-xml("<a><b/><c/></a>"),
  parse-xml("<a><c/><b/></a>")
)]]></eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>By default, order of elements is significant</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[deep-equal(
  parse-xml("<a><b/><c/></a>"),
  parse-xml("<a><c/><b/></a>"),
  options := { 'unordered-elements': #a }
)]]></eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>The <code>unordered-elements</code> option means that the ordering of the children
               of <code>a</code> is ignored.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[deep-equal(
  parse-xml("<para style='bold'><span>x</span></para>"),
  parse-xml("<para style=' bold'> <span>x</span></para>")
)]]></eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>By default, both the leading whitespace in the <code>style</code> attribute
                  and the whitespace text node preceding the <code>span</code> element are significant.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[deep-equal(
  parse-xml("<para style='bold'><span>x</span></para>"),
  parse-xml("<para style=' bold'> <span>x</span></para>"),
  options := { 'whitespace': 'normalize' }
)]]></eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>The <code>whitespace</code> option causes both the leading space
                  in the attribute value and the whitespace preceding the 
                  <code>span</code> element to be ignored.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>deep-equal(
  (1, 2, 3), 
  (1.0007, 1.9998, 3.0005),
  options := { 'items-equal': fn($x, $y) {
    if (($x, $y) instance of xs:numeric+) {
      abs($x - $y) lt 0.001
    }
  } }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>For numeric values, the callback function tests whether they
               are approximately equal. For any other items, it returns the empty sequence,
               so the normal comparison rules apply.</fos:postamble>
            </fos:test>
            
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>deep-equal(
  (1, 2, 3, 4, 5), 
  (1, 2, 3, 8, 5),
  options := { 'items-equal': fn($x, $y) {
    trace((), `comparing { $x } and { $y }`)
  } }
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>The callback function traces which items are being compared,
                  without changing the result of the comparison.</fos:postamble>
            </fos:test>
            
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="930" PR="933" date="2024-01-16">
            <p>When comments and processing instructions are ignored, any text nodes either side of the
            comment or processing instruction are now merged prior to comparison.</p>
         </fos:change>
         <fos:change issue="934 1167" PR="1191" date="2024-05-21">
            <p>The <code>$options</code> parameter has been added, 
               absorbing the <code>$collation</code> parameter.</p>
         </fos:change>
         <fos:change issue="99 1142" PR="1120 1150" date="2024-04-09">
            <p>A callback function can be supplied for comparing individual items.</p>
         </fos:change>
         <fos:change issue="2139" PR="2168" date="2025-08-19"><p>Atomic items of types <code>xs:hexBinary</code> 
            and <code>xs:base64Binary</code> are now mutually comparable. In rare cases, where an
            application uses both types and assumes they are distinct, this can represent a backwards
            incompatibility.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   
   
   <fos:function name="count" prefix="fn">
      <fos:signatures>
         <fos:proto name="count" return-type="xs:integer">
            <fos:arg name="input" type="item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of items in a sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the number of items in <code>$input</code>.</p>
      </fos:rules>
      <fos:equivalent style="dm-primitive">
         dm:count($input)
      </fos:equivalent>
      <fos:notes>
         <p>The function returns <code>0</code> if <code>$input</code> is the empty sequence.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="tree" id="v-count-tree"><![CDATA[<doc><chap><p/><p/><p/></chap></doc>]]></fos:variable>
         <fos:variable name="seq2" id="v-count-seq2" select="(98.5, 98.3, 98.9)"/>
         <fos:variable name="seq3" id="v-count-seq3" select="()"/>
         <fos:example>
            <fos:test use="v-count-tree" spec="XQuery">
               <fos:expression>count($tree//chap/p)</fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-count-seq3">
               <fos:expression>count($seq3)</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-count-seq2">
               <fos:expression>count($seq2)</fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-count-seq2">
               <fos:expression>count($seq2[. &gt; 100])</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>count([])</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>count([ 1, 2, 3 ])</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>        
      </fos:examples>
   </fos:function>
   <fos:function name="avg" prefix="fn">
      <fos:signatures>
         <fos:proto name="avg" return-type="xs:anyAtomicType?">
            <fos:arg name="values" type="xs:anyAtomicType*" usage="absorption"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the average of the values in the input sequence <code>$values</code>, that is, the
            sum of the values divided by the number of values.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$values</code> is the empty sequence, the empty sequence is returned.</p>
         <p>Any item in <code>$values</code> that is an instance of <code>xs:untypedAtomic</code> 
            is cast to <code>xs:double</code>. </p>
         <p>After this conversion, one of the following conditions must be true:</p>
         <olist>
            <item><p>Every item in <code>$values</code> is an instance of <code>xs:yearMonthDuration</code>.</p></item>
            <item><p>Every item in <code>$values</code> is an instance of <code>xs:dayTimeDuration</code>.</p></item>
            <item><p>Every item in <code>$values</code> is an instance of <code>xs:numeric</code>.</p></item>
         </olist>
         

         <p>The function returns the average of the values as <code>sum($values) div
            count($values)</code>; but the implementation may use an otherwise equivalent algorithm
            that avoids arithmetic overflow. Note that the <function>fn:sum</function> function
            allows the input sequence to be reordered, which may affect the result in edge cases
            when the sequence contains a mixture of different numeric types.</p>

      </fos:rules>
      <fos:errors>
         <p>A type error is raised <errorref class="RG" code="0006"
            /> if the input sequence contains
            items of incompatible types, as described above.</p>
      </fos:errors>
      <fos:examples>
         <fos:variable id="v-avg-d1" name="d1" select="xs:yearMonthDuration(&quot;P20Y&quot;)"/>
         <fos:variable id="v-avg-d2" name="d2" select="xs:yearMonthDuration(&quot;P10M&quot;)"/>
         <fos:variable id="v-avg-seq3" name="seq3" select="(3, 4, 5)"/>
         <fos:example>
            <fos:test use="v-avg-seq3">
               <fos:expression>avg($seq3)</fos:expression>
               <fos:result>4.0</fos:result>
               <fos:postamble>The result is of type <code>xs:decimal</code>.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-avg-d1 v-avg-d2">
               <fos:expression>avg(($d1, $d2))</fos:expression>
               <fos:result>xs:yearMonthDuration("P10Y5M")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>avg(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>avg((xs:float('INF'), xs:float('-INF')))</fos:expression>
               <fos:result>xs:float('NaN')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-avg-seq3">
               <fos:expression>avg(($seq3, xs:float('NaN')))</fos:expression>
               <fos:result>xs:float('NaN')</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-avg-d1 v-avg-seq3">
               <fos:expression>fn:avg(($d1, $seq3))</fos:expression>
               <fos:error-result error-code="FORG0006"/>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1682" PR="1734" date="2025-01-27">
            <p>In 3.1, given a mixed input sequence such as (1, 3, 4.2e0), the specification 
            was unclear whether it was permitted to add the first two integer items using
            integer arithmetic, rather than converting all items to doubles before
            performing any arithmetic. The 4.0 specification is clear that this is
            permitted; but since the items can be reordered before being added, this
            is not required.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="max" prefix="fn">
      <fos:signatures>
         <fos:proto name="max" return-type="xs:anyAtomicType?">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a value that is greater than or equal to every other value appearing in the input sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>Any item in <code>$values</code> that is an instance of <code>xs:untypedAtomic</code>
            is first cast to <code>xs:double</code>. The resulting sequence is referred to as the
            converted sequence.</p>
         
         <p>All pairs of values in the converted sequence must be mutually comparable. Two values <var>A</var>
            and <var>B</var> are mutually
            comparable if <code>fn:compare(<var>A</var>, <var>B</var>)</code> raises no error.</p>
         
         
         <p>If the converted sequence is empty, the function returns the empty sequence.</p>
         
         <p>If the converted sequence contains the value <code>NaN</code>, the value
            <code>NaN</code> is returned
            <phrase>(as an <code>xs:float</code> or <code>xs:double</code> as appropriate)</phrase>.</p>
         
         <p>Two items <var>A</var>
            and <var>B</var> from the converted sequence are compared 
            by calling <code>fn:compare(<var>A</var>, <var>B</var>, $collation)</code>, 
            where <code>$collation</code>
               is determined by the rules in <specref ref="choosing-a-collation"/>:</p>
         
         <p>The result of the function is a value from the converted sequence that is greater than 
            or equal to every other value under the above rules. If there is more than one such value, then it is 
            <termref def="implementation-dependent">implementation-dependent</termref>
            which of them is returned.</p>
         
         
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <errorref class="RG" code="0006"
         /> if the input sequence contains
            items of incompatible types, as described above.</p>
      </fos:errors>
      <fos:notes>
         <p>If there are two or items that are
            “equal highest”, the specific item whose value is returned is <termref
               def="implementation-dependent"
               >implementation-dependent</termref>. This can arise for example if two different strings
            compare equal under the selected collation, or if two different <code>xs:dateTime</code>
            values compare equal despite being in different timezones.</p>
         <p>If the converted sequence contains exactly one value then that value is returned.</p>
         <p>The default type when the <function>fn:max</function> function is applied to
            <code>xs:untypedAtomic</code> values is <code>xs:double</code>. This differs from the
            default type for operators such as <code>lt</code>, and for sorting in XQuery and XSLT,
            which is <code>xs:string</code>.</p>
         <p>In version 4.0, if <code>$values</code> is a sequence of <code>xs:decimal</code> values
            (including the case where it is a sequence of <code>xs:integer</code> values), then
            the result will be one of these <code>xs:decimal</code> or <code>xs:integer</code> values. 
            In earlier versions it would
            be the result of converting this <code>xs:decimal</code> to <code>xs:float</code> or <code>xs:double</code>.</p>
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>max((3, 2, 1))</fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>max([ 3, 2, 1 ])</fos:expression>
               <fos:result>3</fos:result>
               <fos:postamble>Arrays are atomized</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>max((
  xs:integer(5),
  xs:float(5),
  xs:double(0)
))</fos:expression>
               <fos:result>5</fos:result>
               <fos:postamble>The result may be either the <code>xs:integer</code> or the <code>xs:float</code>,
                  since they are equal.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>max((
  xs:float(0.0E0),
  xs:float(-0.0E0)
))</fos:expression>
               <fos:result>xs:float(0.0e0)</fos:result>
               <fos:postamble>The result may be either positive or negative zero, since they are equal.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>max((
  current-date(),
  xs:date("2100-01-01")
))</fos:expression>
               <fos:result>xs:date("2100-01-01")</fos:result>
               <fos:postamble>Assuming that the current date is during the 21st century.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>max(("a", "b", "c"))</fos:expression>
               <fos:result>"c"</fos:result>
               <fos:postamble>Assuming a typical default collation.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>max((3, 4, "Zero"))</fos:expression>
               <fos:error-result error-code="FORG0006"/>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="866" PR="881" date="2023-12-06">
            <p>The way that <function>fn:min</function> and <function>fn:max</function> compare numeric values of different types
              has changed. The most noticeable effect is that when these functions are applied to a sequence of
                 <code>xs:integer</code> or <code>xs:decimal</code> values, the result is an <code>xs:integer</code> or 
                 <code>xs:decimal</code>, rather than the result of converting this to an <code>xs:float</code> 
               or <code>xs:double</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
 
   <fos:function name="min" prefix="fn">
      <fos:signatures>
         <fos:proto name="min" return-type="xs:anyAtomicType?">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a value that is less than or equal to every other value appearing in the input sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>Any item in <code>$values</code> that is an instance of <code>xs:untypedAtomic</code>
            is first cast to <code>xs:double</code>. The resulting sequence is referred to as the
            converted sequence.</p>
         
         <p>All pairs of values in the converted sequence must be mutually comparable. Two values <var>A</var>
            and <var>B</var> are mutually
            comparable if <code>fn:compare(<var>A</var>, <var>B</var>)</code> raises no error.</p>
         
         
         <p>If the converted sequence is empty, the function returns the empty sequence.</p>
         
         <p>If the converted sequence contains the value <code>NaN</code>, the value
            <code>NaN</code> is returned
            <phrase>(as an <code>xs:float</code> or <code>xs:double</code> as appropriate)</phrase>.</p>
         
         <p>Two items <var>A</var>
            and <var>B</var> from the converted sequence are compared 
            by calling <code>fn:compare(<var>A</var>, <var>B</var>, $collation)</code>, 
            where <code>$collation</code>
               is determined by the rules in <specref ref="choosing-a-collation"/>:</p>
         
         <p>The result of the function is a value from the converted sequence that is less than 
            or equal to every other value under the above rules. If there is more than one such value, then it is 
            <termref def="implementation-dependent">implementation-dependent</termref>
            which of them is returned.</p>

 
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <errorref class="RG" code="0006"
            /> if the input sequence contains
            items of incompatible types, as described above.</p>
      </fos:errors>
      <fos:notes>
         <p>If there are two or items that are
            “equal lowest”, the specific item whose value is returned is <termref
               def="implementation-dependent"
               >implementation-dependent</termref>. This can arise for example if two different strings
            compare equal under the selected collation, or if two different <code>xs:dateTime</code>
            values compare equal despite being in different timezones.</p>
         <p>If the converted sequence contains exactly one value then that value is returned.</p>
         <p>The default type when the <function>fn:min</function> function is applied to
               <code>xs:untypedAtomic</code> values is <code>xs:double</code>. This differs from the
            default type for operators such as <code>lt</code>, and for sorting in XQuery and XSLT,
            which is <code>xs:string</code>.</p>
         <p>In version 4.0, if <code>$values</code> is a sequence of <code>xs:decimal</code> values
            (including the case where it is a sequence of <code>xs:integer</code> values), then
            the result will be one of these <code>xs:decimal</code> or <code>xs:integer</code> values. 
            In earlier versions it would
            be the result of converting this <code>xs:decimal</code> to <code>xs:float</code> 
            or <code>xs:double</code>.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>min((3, 4, 5))</fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>min([ 3, 4, 5 ])</fos:expression>
               <fos:result>3</fos:result>
               <fos:postamble>Arrays are atomized</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>min((
  xs:integer(5),
  xs:float(5),
  xs:double(10)
))</fos:expression>
               <fos:result>5</fos:result>
               <fos:postamble>The result may be either the <code>xs:integer</code> or the <code>xs:float</code>,
               since they are equal.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>min((
  xs:float(0.0E0),
  xs:float(-0.0E0)
))</fos:expression>
               <fos:result>xs:float(0.0e0)</fos:result>
               <fos:postamble>The result may be either positive or negative zero, since they are equal.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>min((
  current-date(),
  xs:date("1900-01-01")
))</fos:expression>
               <fos:result>xs:date("1900-01-01")</fos:result>
               <fos:postamble>Assuming that the current date is set to a reasonable
                  value.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>min(("a", "b", "c"))</fos:expression>
               <fos:result>"a"</fos:result>
               <fos:postamble>Assuming a typical default collation.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>min((3, 4, "Zero"))</fos:expression>
               <fos:error-result error-code="FORG0006"/>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="866" PR="881" date="2023-12-06">
            <p>The way that <function>fn:min</function> and <function>fn:max</function> compare numeric values of different types
              has changed. The most noticeable effect is that when these functions are applied to a sequence of
                 <code>xs:integer</code> or <code>xs:decimal</code> values, the result is an <code>xs:integer</code> or 
                 <code>xs:decimal</code>, rather than the result of converting this to an <code>xs:float</code> or 
               <code>xs:double</code>.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="sum" prefix="fn">
      <fos:signatures>
         <fos:proto name="sum" return-type="xs:anyAtomicType?">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="zero" type="xs:anyAtomicType?" default="0"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a value obtained by adding together the values in <code>$values</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>Any value of type <code>xs:untypedAtomic</code> in <code>$values</code> is cast to
               <code>xs:double</code>. The items in the resulting sequence may be reordered in an
            arbitrary order. The resulting sequence is referred to below as the converted
            sequence.</p>
         <p>If the converted sequence is empty, then the function returns
            the value of the argument <code>$zero</code>.</p>
         <p>In other cases the items in the converted sequence are added pairwise according
         the rules of the <code>+</code> operator.</p>

         <p>Specifically, the result of the function is the value of the
            expression:</p>
         <eg xml:space="preserve">
if (empty($c)) then $zero
else if (count($c) eq 1) then $c
else head($c) + sum(tail($c))</eg>
         <p>where <code>$c</code> is the converted sequence.</p>
         
         <p>This has the effect that a type error will occur unless one of the following
         conditions is satisfied:</p>
         
          <olist>
            <item><p>Every item in <code>$values</code> is an instance of <code>xs:yearMonthDuration</code>.</p></item>
            <item><p>Every item in <code>$values</code> is an instance of <code>xs:dayTimeDuration</code>.</p></item>
            <item><p>Every item in <code>$values</code> is an instance of <code>xs:numeric</code>.</p></item>
         </olist>
         
         

      </fos:rules>
      <fos:errors>
         <p>A type error is raised <errorref class="RG" code="0006"
            /> if the input sequence contains
            items of incompatible types, as described above.</p>

      </fos:errors>
      <fos:notes>
         <p>The second argument allows an appropriate value to be defined to represent the sum of an
            empty sequence. For example, when summing a sequence of durations it would be
            appropriate to return a zero-length duration of the appropriate type. This argument is
            necessary because a system that does dynamic typing cannot distinguish “an empty
            sequence of integers", for example, from “an empty sequence of durations”.</p>
         <p diff="add" at="2023-01-17">The explicit or implicit value of 
            the <code>$zero</code> argument is used only when the input sequence is empty, not
            when a non-empty sequence sums to zero. For example, <code>sum((-1, +1), xs:double('NaN'))</code>
            returns the <code>xs:integer</code> value <code>0</code>, not <code>NaN</code>.</p>
         <p>The sum of a sequence of integers will be an integer, while the
            sum of a numeric sequence that includes at least one <code>xs:double</code> will be an
               <code>xs:double</code>.</p>
         <p>If the converted sequence contains exactly one value then that value is returned.</p>
         <p>If the converted sequence contains the value <code>NaN</code>, <code>NaN</code> is
            returned.</p>
         <p>In edge cases the fact that the input sequence may be reordered makes the result
            slightly unpredictable. For example, if the input contains two <code>xs:decimal</code>
            values and an <code>xs:float</code>, then the decimal values might be added using
            decimal arithmetic, or they might both be converted to <code>xs:float</code> 
            (potentially losing precision) before any arithmetic is performed.
            </p>
         
         
      </fos:notes>
      <fos:examples>
         <fos:variable name="d1" id="v-sum-d1" select="xs:yearMonthDuration(&quot;P20Y&quot;)"/>
         <fos:variable name="d2" id="v-sum-d2" select="xs:yearMonthDuration(&quot;P10M&quot;)"/>
         <fos:variable name="seq1" id="v-sum-seq1" select="($d1, $d2)"/>
         <fos:variable name="seq3" id="v-sum-seq3" select="(3, 4, 5)"/>
         <fos:example>
            <fos:test use="v-sum-d1 v-sum-d2">
               <fos:expression>sum(($d1, $d2))</fos:expression>
               <fos:result>xs:yearMonthDuration("P20Y10M")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-sum-d1 v-sum-d2 v-sum-seq1">
               <fos:expression><eg>sum(
  $seq1[. lt xs:yearMonthDuration('P3M')],
  xs:yearMonthDuration('P0M')
)</eg></fos:expression>
               <fos:result>xs:yearMonthDuration("P0M")</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-sum-seq3">
               <fos:expression>sum($seq3)</fos:expression>
               <fos:result>12</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>sum(())</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>sum((),())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>sum((1 to 100)[. lt 0], 0) </fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-sum-d1 v-sum-d2">
               <fos:expression>sum(($d1, $d2), "ein Augenblick")</fos:expression>
               <fos:result>xs:yearMonthDuration("P20Y10M")</fos:result>
               <fos:postamble>There is no requirement that the <code>$zero</code> value should be
                  the same type as the items in <code>$value</code>, or even that it should belong to
                  a type that supports addition.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>sum([ 1, 2, 3 ])</fos:expression>
               <fos:result>6</fos:result>
               <fos:postamble>Atomizing an array returns the sequence obtained by atomizing its members.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>sum([ [ 1, 2 ], [ 3, 4 ] ])</fos:expression>
               <fos:result>10</fos:result>
               <fos:postamble>Atomizing an array returns the sequence obtained by atomizing its members.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-sum-d1">
               <fos:expression>fn:sum(($d1, 9E1))</fos:expression>
               <fos:error-result error-code="FORG0006"/>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1682" PR="1734" date="2025-01-27">
            <p>In 3.1, given a mixed input sequence such as (1, 3, 4.2e0), the specification 
            was unclear whether it was permitted to add the first two integer items using
            integer arithmetic, rather than converting all items to doubles before
            performing any arithmetic. The 4.0 specification is clear that this is
            permitted; but since the items can be reordered before being added, this
            is not required.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="id" prefix="fn">
      <fos:signatures>
         <fos:proto name="id" return-type="element()*">
            <fos:arg name="values" type="xs:string*"/>
            <fos:arg name="node" type="node()" default="." usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the sequence of element nodes that have an <code>ID</code> value matching the
            value of one or more of the <code>IDREF</code> values supplied in <code>$values</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence, in document order with duplicates eliminated,
            containing every element node <code>E</code> that satisfies all the following
            conditions:</p>
         <olist>
            <item>
               <p>
                  <code>E</code> is in the target document. The target document is the document
                  containing <code>$node</code>.</p>
            </item>
            <item>
               <p><code>E</code> has an <code>ID</code> value equal to one of the candidate
                     <code>IDREF</code> values, where:</p>
               <ulist>
                  <item>
                     <p> An element has an <code>ID</code> value equal to <code>V</code> if either
                        or both of the following conditions are true:</p>
                     <ulist>
                        <item>
                           <p>The <code>is-id</code> property (See <xspecref spec="DM40"
                                 ref="dm-is-id"
                                 />.) of the element node is <code>true</code>, and the typed value
                              of the element node is equal to <code>V</code> under the rules of the
                                 <code>eq</code> operator using the Unicode codepoint collation
                                 (<code>http://www.w3.org/2005/xpath-functions/collation/codepoint</code>).</p>
                        </item>
                        <item>
                           <p>The element has an attribute node whose <code>is-id</code> property
                              (See <xspecref
                                 spec="DM40" ref="dm-is-id"
                                 />.) is <code>true</code> and whose typed
                              value is equal to <code>V</code> under the rules of the
                                 <code>eq</code> operator using the Unicode code point collation
                                 (<code>http://www.w3.org/2005/xpath-functions/collation/codepoint</code>).</p>
                        </item>
                     </ulist>
                  </item>
                  <item>
                     <p> Each <code>xs:string</code> in <code>$values</code> is parsed as if it were of
                        type <code>IDREFS</code>, that is, each <code>xs:string</code> in
                        <code>$values</code> is treated as a whitespace-separated sequence of
                        tokens, each acting as an <code>IDREF</code>. These tokens are then included
                        in the list of candidate <code>IDREF</code>s. If any of the tokens is not a
                        lexically valid <code>IDREF</code> (that is, if it is not lexically an
                           <code>xs:NCName</code>), it is ignored. Formally, the candidate
                           <code>IDREF</code> values are the strings in the sequence given by the
                        expression:</p>
                     <eg xml:space="preserve">for $s in $values
return tokenize(normalize-space($s), ' ')[. castable as xs:IDREF]</eg>

                  </item>
               </ulist>
            </item>
            <item>
               <p>If several elements have the same <code>ID</code> value, then <code>E</code> is
                  the one that is first in document order.</p>
            </item>
         </olist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0001" type="dynamic"
               /> if
               <code>$node</code>, or the context value if the second argument is absent, is a node
            in a tree whose root is not a document node.</p>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not a single node, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>The effect of this function is anomalous in respect of element nodes with the
               <code>is-id</code> property. For legacy reasons, this function returns the element
            that has the <code>is-id</code> property, whereas it would be more appropriate to return
            its parent, that being the element that is uniquely identified by the ID. A new function
               <function>fn:element-with-id</function> has been introduced with the desired
            behavior.</p>

         <p> If the data model is constructed from an Infoset, an attribute will have the
               <code>is-id</code> property if the corresponding attribute in the Infoset had an
            attribute type of <code>ID</code>: typically this means the attribute was declared as an
               <code>ID</code> in a DTD.</p>
         <!--Text replaced by erratum E13 change 1"-->
         <p> If the data model is constructed from a PSVI, an element or attribute will have the
               <code>is-id</code> property if its typed value is a single atomic item of type
               <code>xs:ID</code> or a type derived by restriction from <code>xs:ID</code>.</p>
         <!--End of text replaced by erratum E13-->
         <p> No error is raised in respect of a candidate <code>IDREF</code> value that does not
            match the <code>ID</code> of any element in the document. If no candidate
               <code>IDREF</code> value matches the <code>ID</code> value of any element, the
            function returns the empty sequence.</p>
         <p> It is not necessary that the supplied argument should have type <code>xs:IDREF</code>
            or <code>xs:IDREFS</code>, or that it should be derived from a node with the
               <code>is-idrefs</code> property.</p>
         <p> An element may have more than one <code>ID</code> value. This can occur with synthetic
            data models or with data models constructed from a PSVI where the element and one of its
            attributes are both typed as <code>xs:ID</code>.</p>
         <p> If the source document is well-formed but not valid, it is possible for two or more
            elements to have the same <code>ID</code> value. In this situation, the function will
            select the first such element.</p>
         <p> It is also possible in a well-formed but invalid document to have an element or
            attribute that has the <code>is-id</code> property but whose value does not conform to
            the lexical rules for the <code>xs:ID</code> type. Such a node will never be selected by
            this function.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="emp" id="v-id-emp" as="document-node()"><![CDATA[validate lax {
  document {
    <employee xml:id="ID21256"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
              xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <empnr xsi:type="xs:ID">E21256</empnr>
      <first>John</first>
      <last>Brown</last>
    </employee>
  }
}]]></fos:variable>
         <fos:example>
            <fos:test xslt-version="3.0" use="v-id-emp" spec="XQuery" schema-aware="true">
               <fos:expression><eg>$emp/id('ID21256')/name()</eg></fos:expression>
               <fos:result>"employee"</fos:result>
               <fos:postamble>The <code>xml:id</code> attribute has the <code>is-id</code> property,
                  so the employee element is selected.</fos:postamble>
            </fos:test>
            <fos:test xslt-version="3.0" use="v-id-emp" spec="XQuery" schema-aware="true">
               <fos:expression><eg>$emp/id('E21256')/name()</eg></fos:expression>
               <fos:result>"empnr"</fos:result>
               <fos:postamble>Assuming the <code>empnr</code> element is given the type
                     <code>xs:ID</code> as a result of schema validation, the element will have the
                     <code>is-id</code> property and is therefore selected. Note the difference from
                  the behavior of <function>fn:element-with-id</function>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="element-with-id" prefix="fn">
      <fos:signatures>
         <fos:proto name="element-with-id" return-type="element()*">
            <fos:arg name="values" type="xs:string*"/>
            <fos:arg name="node" type="node()" default="." usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p> Returns the sequence of element nodes that have an <code>ID</code> value matching the
            value of one or more of the <code>IDREF</code> values supplied in <code>$values</code>.</p>
      </fos:summary>
      <fos:rules>

         <note>
            <p>The effect of this function is identical to <function>fn:id</function> in respect of
               elements that have an attribute with the <code>is-id</code> property. However, it
               behaves differently in respect of element nodes with the <code>is-id</code> property.
               Whereas the <function>fn:id</function> function, for legacy reasons, returns the element that has the
                  <code>is-id</code> property, this function returns the element identified by the ID,
               which is the parent of the element having the <code>is-id</code> property.</p>
         </note>
         <p>The function returns a sequence, in document order with duplicates eliminated,
            containing every element node <code>E</code> that satisfies all the following
            conditions:</p>
         <olist>
            <item>
               <p>
                  <code>E</code> is in the target document. The target document is the document
                  containing <code>$node</code>.</p>
            </item>
            <item>
               <p><code>E</code> has an <code>ID</code> value equal to one of the candidate
                     <code>IDREF</code> values, where:</p>
               <ulist>
                  <item>
                     <p> An element has an <code>ID</code> value equal to <code>V</code> if either
                        or both of the following conditions are true:</p>
                     <ulist>
                        <item>
                           <p>The element has an child element node whose <code>is-id</code>
                              property (See <xspecref
                                 spec="DM40" ref="dm-is-id"
                                 />.) is <code>true</code> and
                              whose typed value is equal to <code>V</code> under the rules of the
                                 <code>eq</code> operator using the Unicode code point collation
                                 (<code>http://www.w3.org/2005/xpath-functions/collation/codepoint</code>).</p>
                        </item>
                        <item>
                           <p>The element has an attribute node whose <code>is-id</code> property
                              (See <xspecref
                                 spec="DM40" ref="dm-is-id"
                                 />.) is <code>true</code> and whose typed
                              value is equal to <code>V</code> under the rules of the
                                 <code>eq</code> operator using the Unicode code point collation
                                 (<code>http://www.w3.org/2005/xpath-functions/collation/codepoint</code>).</p>
                        </item>
                     </ulist>
                  </item>
                  <item>
                     <p>Each <code>xs:string</code> in <code>$values</code> is parsed as if it were of
                        type <code>IDREFS</code>, that is, each <code>xs:string</code> in
                        <code>$values</code> is treated as a whitespace-separated sequence of
                        tokens, each acting as an <code>IDREF</code>. These tokens are then included
                        in the list of candidate <code>IDREF</code>s. If any of the tokens is not a
                        lexically valid <code>IDREF</code> (that is, if it is not lexically an
                           <code>xs:NCName</code>), it is ignored. Formally, the candidate
                           <code>IDREF</code> values are the strings in the sequence given by the
                        expression:</p>
                     <eg xml:space="preserve">for $s in $values
return tokenize(normalize-space($s), ' ')[. castable as xs:IDREF]</eg>
                  </item>
               </ulist>
            </item>
            <item>
               <p> If several elements have the same <code>ID</code> value, then <code>E</code> is
                  the one that is first in document order.</p>
            </item>
         </olist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0001" type="dynamic"
               /> if <code>$node</code>, or the context value if the second argument is omitted, is a node
            in a tree whose root is not a document node.</p>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>

               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>, type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not a single node, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>This function is equivalent to the <function>fn:id</function> function except when dealing with
            ID-valued element nodes. Whereas the <function>fn:id</function> function selects the element
            containing the identifier, this function selects its parent.</p>
         <p>If the data model is constructed from an Infoset, an attribute will have the
               <code>is-id</code> property if the corresponding attribute in the Infoset had an
            attribute type of <code>ID</code>: typically this means the attribute was declared as an
               <code>ID</code> in a DTD.</p>
         <!--Text replaced by erratum E13 change 1"-->
         <p> If the data model is constructed from a PSVI, an element or attribute will have the
               <code>is-id</code> property if its typed value is a single atomic item of type
               <code>xs:ID</code> or a type derived by restriction from <code>xs:ID</code>.</p>
         <!--End of text replaced by erratum E13-->
         <p> No error is raised in respect of a candidate <code>IDREF</code> value that does not
            match the <code>ID</code> of any element in the document. If no candidate
               <code>IDREF</code> value matches the <code>ID</code> value of any element, the
            function returns the empty sequence.</p>
         <p> It is not necessary that the supplied argument should have type <code>xs:IDREF</code>
            or <code>xs:IDREFS</code>, or that it should be derived from a node with the
               <code>is-idrefs</code> property.</p>
         <p> An element may have more than one <code>ID</code> value. This can occur with synthetic
            data models or with data models constructed from a PSVI where the element and one of its
            attributes are both typed as <code>xs:ID</code>.</p>
         <p> If the source document is well-formed but not valid, it is possible for two or more
            elements to have the same <code>ID</code> value. In this situation, the function will
            select the first such element.</p>
         <p> It is also possible in a well-formed but invalid document to have an element or
            attribute that has the <code>is-id</code> property but whose value does not conform to
            the lexical rules for the <code>xs:ID</code> type. Such a node will never be selected by
            this function.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="emp" as="element()" id="v-element-with-id-emp"><![CDATA[validate lax {    
  document {
    <employee xml:id="ID21256"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
              xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <empnr xsi:type="xs:ID">E21256</empnr>
      <first>John</first>
      <last>Brown</last>
    </employee>
  }
}]]>
         </fos:variable>
         <fos:example>
            <fos:test xslt-version="3.0" use="v-element-with-id-emp" spec="XQuery" schema-aware="true">
               <fos:expression><eg>$emp/element-with-id('ID21256')/name()</eg></fos:expression>
               <fos:result>"employee"</fos:result>
               <fos:postamble>The <code>xml:id</code> attribute has the <code>is-id</code> property,
                  so the employee element is selected.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0" use="v-element-with-id-emp" spec="XQuery" schema-aware="true">
               <fos:expression>$emp/element-with-id('E21256')/name()</fos:expression>
               <fos:result>"employee"</fos:result>
               <fos:postamble>Assuming the <code>empnr</code> element is given the type
                     <code>xs:ID</code> as a result of schema validation, the element will have the
                     <code>is-id</code> property and is therefore its parent is selected. Note the
                  difference from the behavior of <function>fn:id</function>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="idref" prefix="fn">
      <fos:signatures>
         <fos:proto name="idref" return-type="node()*">
            <fos:arg name="values" type="xs:string*"/>
            <fos:arg name="node" type="node()" default="." usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the sequence of element or attribute nodes with an <code>IDREF</code> value
            matching the value of one or more of the <code>ID</code> values supplied in
               <code>$values</code>.</p>
      </fos:summary>
      <fos:rules>
         <p> The function returns a sequence, in document order with duplicates eliminated,
            containing every element or attribute node <code>$N</code> that satisfies all the
            following conditions:</p>
         <olist>
            <item>
               <p><code>$N</code> is in the target document. The target document is the document
                  containing <code>$node</code>.</p>
            </item>
            <item>
               <p><code>$N</code> has an <code>IDREF</code> value equal to one of the candidate
                     <code>ID</code> values, where:</p>
               <ulist>
                  <item>
                     <p>A node <code>$N</code> has an <code>IDREF</code> value equal to
                           <code>V</code> if both of the following conditions are true:</p>
                     <ulist>
                        <item>
                           <p>The <code>is-idrefs</code> property (see <xspecref spec="DM40"
                                 ref="dm-is-idrefs"/>) of <code>$N</code> is <code>true</code>.</p>
                        </item>
                        <item>
                           <p>The sequence <!--Text replaced by erratum E29 change 1"--></p>
                           <eg xml:space="preserve">tokenize(normalize-space(string($N)), ' ')</eg>
                           <!--End of text replaced by erratum E29-->
                           <p>contains a string that is
                              equal to <code>V</code> under the rules of the <code>eq</code>
                              operator using the Unicode code point collation
                                 (<code>http://www.w3.org/2005/xpath-functions/collation/codepoint</code>).</p>
                        </item>
                     </ulist>
                  </item>
                  <item>
                     <p>Each <code>xs:string</code> in <code>$values</code> is parsed as if it were of
                        lexically of type <code>xs:ID</code>. These <code>xs:string</code>s are then
                        included in the list of candidate <code>xs:ID</code>s. If any of the strings
                        in <code>$values</code> is not a lexically valid <code>xs:ID</code> (that is,
                        if it is not lexically an <code>xs:NCName</code>), it is ignored. More
                        formally, the candidate <code>ID</code> values are the strings in the
                        sequence:</p>
                     <eg xml:space="preserve">$values[. castable as xs:NCName]</eg>
                  </item>
               </ulist>
            </item>
         </olist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0001" type="dynamic"
               /> if
               <code>$node</code>, or the context value if the second argument is omitted, is a node
            in a tree whose root is not a document node. </p>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not a single node, type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p> An element or attribute typically acquires the <code>is-idrefs</code> property by being
            validated against the schema type <code>xs:IDREF</code> or <code>xs:IDREFS</code>, or
            (for attributes only) by being described as of type <code>IDREF</code> or
               <code>IDREFS</code> in a DTD.</p>
         <p>Because the function is sensitive to the way in which the data model
         is constructed, calls on this function are not always interoperable.</p>
         <p> No error is raised in respect of a candidate <code>ID</code> value that does not match
            the <code>IDREF</code> value of any element or attribute in the document. If no
            candidate <code>ID</code> value matches the <code>IDREF</code> value of any element or
            attribute, the function returns the empty sequence.</p>
         <p> It is possible for two or more nodes to have an <code>IDREF</code> value that matches a
            given candidate <code>ID</code> value. In this situation, the function will return all
            such nodes. However, each matching node will be returned at most once, regardless how
            many candidate <code>ID</code> values it matches.</p>
         <p> It is possible in a well-formed but invalid document to have a node whose
               <code>is-idrefs</code> property is <code>true</code> but that does not conform to the lexical
            rules for the <code>xs:IDREF</code> type. The effect of the above rules is that
            ill-formed candidate <code>ID</code> values and ill-formed <code>IDREF</code> values are
            ignored.</p>
         <p>If the data model is constructed from a PSVI, the typed value of a node that has the
               <code>is-idrefs</code> property will contain at least one atomic item of type
               <code>xs:IDREF</code> (or a type derived by restriction from <code>xs:IDREF</code>).
            It may also contain atomic items of other types. These atomic items are treated as
            candidate <code>ID</code> values <phrase>if two conditions are met: their lexical form must be valid as an
               <code>xs:NCName</code>, and there must be at least one instance of <code>xs:IDREF</code>
            in the typed value of the node. If these conditions are not satisfied, such values are ignored.</phrase></p>

      </fos:notes>
      <fos:examples>
         <fos:variable name="emp" as="element()" id="v-idref-emp"><![CDATA[validate lax {  
  document {    
    <employees xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
               xmlns:xs="http://www.w3.org/2001/XMLSchema">  
      <employee xml:id="ID21256">
        <empnr xsi:type="xs:ID">E21256</empnr>
        <first>Anil</first>
        <last>Singh</last>
        <deputy xsi:type="xs:IDREF">E30561</deputy>
      </employee>
      <employee xml:id="ID30561">
        <empnr xsi:type="xs:ID">E30561</empnr>
        <first>John</first>
        <last>Brown</last>
        <manager xsi:type="xs:IDREF">ID21256</manager>
      </employee>
    </employees>
  }
}]]>
         </fos:variable>
         <fos:example>
            <fos:test xslt-version="3.0" use="v-idref-emp" spec="XQuery" schema-aware="true">
               <fos:expression><eg>$emp/(
  element-with-id('ID21256')/@xml:id => idref()
)/ancestor::employee/last
=> string()</eg></fos:expression>
               <fos:result>"Brown"</fos:result>
               <fos:postamble>Assuming that <code>manager</code> has the is-idref property, the call on <function>fn:idref</function> selects
                  the <code>manager</code> element. If, instead, the <code>manager</code> had a <code>ref</code>
               attribute with the is-idref property, the call on <function>fn:idref</function> would select the attribute node.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test xslt-version="3.0" use="v-idref-emp" spec="XQuery" schema-aware="true">
               <fos:expression><eg>$emp/(
  element-with-id('E30561')/empnr => idref()
)/ancestor::employee/last
=> string()</eg></fos:expression>
               <fos:result>"Singh"</fos:result>
               <fos:postamble>Assuming that <code>employee/deputy</code> has the is-idref property, the call on <function>fn:idref</function> selects
                  the <code>deputy</code> element.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="doc" prefix="fn">
      <fos:signatures>
         <fos:proto name="doc" return-type="document-node()?">
            <fos:arg name="source" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="available-documents executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Retrieves a document using a URI supplied as an <code>xs:string</code>, and returns the
            corresponding document node.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$source</code> is the empty sequence, the result is the empty sequence.</p>
         <p>If <code>$source</code> is a relative URI reference, it is resolved relative to the value

            of the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> property 
            from the dynamic context of the caller. The resulting absolute URI is
            promoted to an <code>xs:string</code>.</p>
         
         <p>The way in which an absolute URI is dereferenced to obtain an external resource is 
            described in <xspecref spec="XP40" ref="id-security-resources"/>.</p>
         
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
         
         <p>The URI may include a fragment identifier.</p>
         
         <p>The <code>$options</code> argument defines the detailed behavior of the function.
            The <termref def="option-parameter-conventions"/> apply. The options available
            are as follows:</p>
         
         <fos:options>
            <fos:option key="trusted">
               <fos:meaning>Indicates whether processing the document may cause other
                  external resources to be fetched (including, for example, external entities, an external DTD,
                  or documents referenced using <code>xsi:schemaLocation</code> or
                  XInclude elements).</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false()</fos:default>
               <fos:values>
                  <fos:value value="true">The document may include references to other external
                     resources.
                  </fos:value>
                  <fos:value value="false">The document must not include references to other
                     external resources unless access to these resources has been explicitly
                     enabled.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="dtd-validation">
               <fos:meaning>Determines whether DTD validation takes place.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">The input is parsed using a validating XML parser.
                  The input must contain a <code>DOCTYPE</code> declaration to identify
                  the DTD to be used for validation. The DTD may be internal or external.
                  </fos:value>
                  <fos:value value="false">DTD validation does not take place. However, if a
                     <code>DOCTYPE</code> declaration is present, then it is read, for example
                     to perform entity expansion.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="stable">
               <fos:meaning>Determines whether two calls on the <function>doc</function> function,
               with the same URI, the same options, and the same context, are guaranteed to return
               the same document node. The default value is <code>true</code>, but this may be overridden
               by implementation-defined configuration options.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
               <fos:values>
                  <fos:value value="true">Given the same explicit and implicit arguments, multiple
                     calls return the same document node: that is, the function is <termref def="dt-deterministic"/>.
                  </fos:value>
                  <fos:value value="false">Multiple calls with the same explicit and implicit arguments
                     may return the same document node or different document nodes at the discretion of
                     the implementation.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="strip-space">
               <fos:meaning>Determines whether whitespace-only text nodes are removed
                  from the resulting document. The default is defined by the host language
                  or by the implementation. (Note: in XSLT, the <code>xsl:strip-space</code>
                  and <code>xsl:preserve-space</code> declarations provide detailed control
                  based on the parent element name.)</fos:meaning>
               <fos:type>xs:boolean?</fos:type>
               <fos:default>()</fos:default>
               <fos:values>
                  <fos:value value="true">All whitespace-only text nodes are stripped,
                  unless either (a) they are within the scope of the attribute <code>xml:space="preserve"</code>,
                  or (b) XSD validation identifies that the parent element has a simple type or a complex
                  type with simple content.
                  </fos:value>
                  <fos:value value="false">All whitespace-only text nodes are preserved,
                  unless either (a) DTD validation marks them as ignorable, or (b) XSD validation recognizes
                  the containing element as having element-only or empty content.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="xinclude">
               <fos:meaning>Determines whether any <code>xi:include</code> elements in the input
                  are to be processed using an XInclude processor.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">Any <code>xi:include</code> elements are expanded. If there are
                     <code>xi:include</code> elements and no XInclude processor is available then 
                     a dynamic error is raised.
                  </fos:value>
                  <fos:value value="false">Any <code>xi:include</code> elements are handled as
                     ordinary elements without expansion.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="xsd-validation">
               <fos:meaning>Determines whether XSD validation takes place, using the
                  schema definitions present in the static context. The effect of requesting
               validation is the same as invoking the <function>doc</function> function without
               validation, and then applying an XQuery <code>validate</code> expression to the result,
               with corresponding options.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"skip"</fos:default>
               <fos:values>
                  <fos:value value="strict">Strict XSD validation takes place</fos:value>
                  <fos:value value="lax">Lax XSD validation takes place</fos:value>
                  <fos:value value="skip">No XSD validation takes place</fos:value>
                  <fos:value value="type Q{uri}local">XSD validation takes place against the
                  schema-defined type, present in the static context, that has the given URI
                  and local name.</fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="use-xsi-schema-location">
               <fos:meaning>When XSD validation takes place, determines whether
                  schema components referenced using <code>xsi:schemaLocation</code> or <code>xsi:noNamespaceSchemaLocation</code>
                  attributes within the source document are to be used. The option is ignored
                  if XSD validation does not take place.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">XSD validation uses the schema components referenced 
                  using <code>xsi:schemaLocation</code> or <code>xsi:noNamespaceSchemaLocation</code>
                  attributes in addition to the schema components present in the static context;
                  these components must be compatible as described in <xspecref spec="DM40" ref="schema-consistency"/>.</fos:value>
                  <fos:value value="false">Any <code>xsi:schemaLocation</code> and <code>xsi:noNamespaceSchemaLocation</code>
                  attributes in the document are ignored.</fos:value>
                 
               </fos:values>
            </fos:option>
         </fos:options>
         
         <p>By default, this function is <termref def="dt-deterministic"
            >deterministic</termref>. Two
            calls on this function return the same document node if the same URI Reference (after
            resolution to an absolute URI Reference) is supplied to both calls. Thus, the following
            expression (if it does not raise an error) will always return <code>true</code>:</p>
         <eg xml:space="preserve">doc("foo.xml") is doc("foo.xml")</eg>
         
         
         <note diff="add" at="issue898"><p>This equivalence applies only because the two calls on
            the <function>fn:doc</function> function have the same options and the same 
            static and dynamic context, to the extent this is relevant. 
            If two calls on <function>fn:doc</function>
           have different dynamic contexts, then the mapping from URIs to document
         nodes in the two contexts may differ, which means that different document nodes may be returned
         for the same URI.
         This can happen, for example, if the two calls appear in different XSLT packages with different
         validation options or whitespace-stripping options; one call might produce a schema-validated
         document, the other an untyped document.</p></note>
         <p>The requirement to deliver a deterministic result has performance implications, 
            and for this reason implementations may provide a user option to evaluate
            the function without a guarantee of determinism. The manner in which any such option is
            provided is <termref def="implementation-defined"/>. If the user has not selected such an option, a call
            of the function must either return a deterministic result or must raise a dynamic error
               <errorref
               class="DC" code="0003"/>.</p>

         <note>
            <p>If the <code>$source</code> URI is obtained from a source document, it is generally appropriate to
               resolve it relative to the base URI property of the relevant node in the source
               document. This can be achieved by calling the <function>fn:resolve-uri</function> function,
               and passing the resulting absolute URI as an argument to the <function>fn:doc</function>
               function.</p>
         </note>
         <p>If two calls to this function supply different absolute URI References as arguments, the
            same document node may be returned if the implementation can determine that the two
            arguments refer to the same resource.</p>
         <p> By defining the semantics of this function in terms of a string-to-document-node
            mapping in the dynamic context, the specification is acknowledging that the results of
            this function are outside the purview of the language specification itself, and depend
            entirely on the run-time environment in which the expression is evaluated. This run-time
            environment includes not only an unpredictable collection of resources (“the web”), but
            configurable machinery for locating resources and turning their contents into document
            nodes within the XPath data model. Both the set of resources that are reachable, and the
            mechanisms by which those resources are parsed and validated, are <termref
               def="implementation-dependent">implementation-dependent</termref>.</p>
         <p> One possible processing model for this function is as follows. The resource identified
            by the URI Reference is retrieved. If the resource cannot be retrieved, a dynamic error
            is raised <errorref
               class="DC" code="0002"
               />. The data resulting from the retrieval
            action is then parsed as an XML document and a tree is constructed in accordance with
            the <bibref
               ref="xpath-datamodel-30"
               />. If the top-level media type is known and is
            <code>"text"</code>, the content is parsed in the same way as if the media type were text/xml;
            otherwise, it is parsed in the same way as if the media type were application/xml. If
            the contents cannot be parsed successfully, a dynamic error is raised <errorref
               class="DC" code="0002"
            />. Otherwise, the result of the function is the document node
            at the root of the resulting tree. This tree is then optionally validated against a
            schema.</p>
         <p>Various aspects of this processing are <termref def="implementation-defined"
               >implementation-defined</termref>.
            Implementations may provide external configuration options that allow any aspect of the
            processing to be controlled by the user. In particular:</p>
         <ulist>
            <item>
               <p>The set of URI schemes that the implementation recognizes is
                  implementation-defined. Implementations may allow the mapping of URIs to resources
                  to be configured by the user, using mechanisms such as catalogs or user-written
                  URI handlers.</p>
            </item>
            <item>
               <p>The handling of non-XML media types is implementation-defined. Implementations may
                  allow instances of the data model to be constructed from non-XML resources, under
                  user control.</p>
            </item>
            <item>
               <p>It is <termref def="implementation-defined"
                  >implementation-defined</termref> whether DTD validation and/or schema
                  validation is applied to the source document.</p>
            </item>
            <item>
               <p>Implementations may provide user-defined error handling options that allow
                  processing to continue following an error in retrieving a resource, or in parsing
                  and validating its content. When errors have been handled in this way, the
                  function may return either the empty sequence, or a fallback document provided by
                  the error handler.</p>
            </item>
            <item>
               <p>Implementations may provide user options that relax the requirement for the
                  function to return deterministic results.</p>
            </item>
            <item>
               <p>The effect of a fragment identifier in the supplied URI 
                  is <termref
                     def="implementation-defined"
                  >implementation-defined</termref>. One possible interpretation
               is to treat the fragment identifier as an ID attribute value, and to return a document
               node having the element with the selected ID value as its only child.</p>
            </item>
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error <rfc2119>may</rfc2119> be raised <errorref class="DC" code="0005"
               /> if
               <code>$source</code> is not a valid URI <phrase>reference</phrase>.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
            /> if a relative URI reference
         is supplied, and the base-URI property in the static context is absent.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
               /> if the <term>available
               documents</term> provides no mapping for the absolutized URI.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
            /> if the resource cannot be
            retrieved or cannot be parsed successfully as XML using the selected options.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0003"
            /> if the implementation is
            not able to guarantee that the result of the function will be deterministic, and the
            user has not indicated that an unstable result is acceptable.</p>
      </fos:errors>
      <fos:changes>
         <fos:change issue="898" PR="905" date="2024-01-09">
            <p>The rule that multiple calls on <function>fn:doc</function>
            supplying the same absolute URI must return the same document node has been clarified;
            in particular the rule does not apply if the dynamic context for the two calls requires
            different processing of the documents (such as schema validation or whitespace stripping).</p>
         </fos:change>
         <fos:change issue="1021" PR="1910" date="2025-04-06">
            <p>An <code>$options</code> parameter is added. Note that the rules for the <code>$options</code> parameter
            control aspects of processing that were implementation-defined in earlier versions of this
            specification. An implementation may provide configuration options designed to retain backwards-compatible
            behavior when no explicit options are supplied.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="doc-available" prefix="fn">
      <fos:signatures>
         <fos:proto name="doc-available" return-type="xs:boolean">
            <fos:arg name="source" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="available-documents executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>The function returns <code>true</code> if and only if the function call <code>fn:doc($source, $options)</code>
            would return a document node.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$source</code> is the empty sequence, this function returns <code>false</code>.</p>
         <p>If a call on <code>fn:doc($source, $options)</code> would return a document node, this function
            returns <code>true</code>.</p>
         <p>In all other cases this function returns <code>false</code>. <phrase>This
         includes the case where <phrase>an invalid URI is supplied, and also the case where </phrase>
            a valid relative URI reference is supplied, and cannot be resolved,
         for example because the static base URI is absent.</phrase></p>
         
         <p>The recognized values for <code>$options</code> are the same as for the <function>fn:doc</function>
         function. The <termref def="option-parameter-conventions"/> apply. Note that if the <code>stable</code>
         option is set to <code>true</code>, then a result of <code>true</code> from this function guarantees
         that a call on <function>fn:doc</function> with the same explicit and implicit arguments will succeed, whereas a
         result of <code>false</code> from this function guarantees that the corresponding call on <function>fn:doc</function>
         will fail. Conversely, if the <code>stable</code> option is set to <code>false</code>, then the result of this
         function provides no guarantees regarding the outcome of a call on <function>fn:doc</function> with 
         the same explicit and implicit arguments.</p>
         

      </fos:rules>
      <fos:errors>
         <p>Like any other function, <function>doc-available</function> fails with an error if 
         invalid arguments are supplied: for example if the first argument is not a string, or
         if unrecognized options are included in <code>$options</code>. However, it returns false
         rather than raising an error if the first argument is invalid as a URI.</p>
         <p>The function also returns false (rather than raising an error) if the document is
         unavailable because of processor limitations, for example if schema validation is
         requested and the processor is not schema-aware.</p>
      </fos:errors>
      <fos:changes>
         <fos:change issue="1021" PR="1910" date="2025-04-06">
            <p>An <code>$options</code> parameter is added. Note that the rules for the <code>$options</code> parameter
            control aspects of processing that were implementation-defined in earlier versions of this
            specification. An implementation may provide configuration options designed to retain backwards-compatible
            behavior when no explicit options are supplied.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="collection" prefix="fn">
      <fos:signatures>
         <fos:proto name="collection" return-type="item()*">
            <fos:arg name="source" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="available-collections executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence of items identified by a
            collection URI; or a default collection if no URI is supplied.</p>
      </fos:summary>
      <fos:rules>
         <p>This function takes an <code>xs:string</code> as argument and returns a sequence of
            <phrase>items</phrase> obtained by interpreting <code>$source</code> as an <code>xs:anyURI</code> and
            resolving it according to the mapping specified in <term>available 
               collections</term> described in <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"/>.</p>
         <p>If <phrase><term>available collections</term></phrase> provides a mapping from this string to a
            sequence of items, the function returns that sequence. If <term>available 
               collections</term> maps the string to the empty sequence, then the function returns an
            empty sequence.</p>
         <p>If <code>$source</code> is the empty sequence, the function returns the sequence of
            <phrase>items</phrase> in the default collection in the dynamic context. See <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"/>. </p>
         <p>If <code>$source</code> is a relative URI reference, it is resolved relative to the value
            of the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> property 
            from the dynamic context of the caller. The resulting absolute URI is
            promoted to an <code>xs:string</code>.</p>
         <p>By default, this function is <termref def="dt-deterministic"
               >deterministic</termref>. This
            means that repeated calls on the function with the same argument will return the same
            result. However, for performance reasons, implementations may provide a user option to
            evaluate the function without a guarantee of determinism. The manner in which any such
            option is provided is <termref
               def="implementation-defined"
               >implementation-defined</termref>. If the user has not
            selected such an option, a call to this function must either return a deterministic
            result or must raise a dynamic error <errorref
               class="DC" code="0003"/>.</p>
         <p>There is no requirement that <phrase>any nodes in the result</phrase> should be in document order, nor is
            there a requirement that the result should contain no duplicates.</p>
         
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>


      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
               /> if no URI is supplied and
            the value of the default collection is <xtermref
               ref="dt-absent" spec="DM40">absent</xtermref>.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
            /> if a relative URI reference
            is supplied, and the base-URI property in the static context is absent.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
               /> if <term>available node
               collections</term> provides no mapping for the absolutized URI.</p>
         <p>A dynamic error <phrase><rfc2119>may</rfc2119> be</phrase> raised <errorref class="DC"
               code="0004"/> if <code>$source</code> is not
            a valid <code>xs:anyURI</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>In earlier versions of this specification, the primary use for the <function>fn:collection</function> function
         was to retrieve a collection of XML documents, perhaps held as lexical XML in operating
         system filestore, or perhaps held in an XML database. In this release the concept has
         been generalised to allow other resources to be retrieved: for example JSON documents might
         be returned as arrays or maps, non-XML text files might be returned as strings, and binary
         files might be returned as instances of <code>xs:base64Binary</code>.</p>
         <p>The abstract concept of a collection might be realized in different ways by different
            implementations, and the ways in which URIs map to collections can be equally variable. 
            Specifying resources using URIs is
            useful because URIs are dynamic, can be parameterized, and do not rely on an external
            environment.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="uri-collection" prefix="fn">
      <fos:signatures>
         <fos:proto name="uri-collection" return-type="xs:anyURI*">
            <fos:arg name="source" type="xs:string?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="available-uri-collections executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence of <code>xs:anyURI</code> values representing the URIs in a URI
            collection.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$source</code> is the empty sequence, the function returns the URIs in the
            <term>default URI collection</term> described in <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"/>.</p>
         <p>If <code>$source</code> is a relative URI reference, it is resolved relative to the value
            of the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> property 
            from the dynamic context of the caller. The resulting absolute URI is
            promoted to an <code>xs:string</code>.</p>
         <p>The single-argument form of the function returns the sequence of URIs corresponding to
            the supplied URI in the <term>available URI collections</term> described in
               <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"/>.</p>
         <p>By default, this function is <termref def="dt-deterministic"
               >deterministic</termref>. This
            means that repeated calls on the function with the same argument will return the same
            result. However, for performance reasons, implementations may provide a user option to
            evaluate the function without a guarantee of determinism. The manner in which any such
            option is provided is <termref
               def="implementation-defined"
               >implementation-defined</termref>. If the user has not
            selected such an option, a call to this function must either return a deterministic
            result or must raise a dynamic error <errorref
               class="DC" code="0003"/>.</p>
         <p>There is no requirement that the URIs returned by this function should all be distinct,
            and no assumptions can be made about the order of URIs in the sequence, unless the
            implementation defines otherwise.</p>
         
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
               /> if no URI is supplied (that
            is, if the function is called with no arguments, or with a single argument that
            evaluates to the empty sequence), and the value of the default resource collection is
               <xtermref
               ref="dt-absent" spec="DM40">absent</xtermref>.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
            /> if a relative URI reference
            is supplied, and the base-URI property in the static context is absent.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0002"
               /> if <term>available resource
               collections</term> provides no mapping for the absolutized URI.</p>
         <p>A dynamic error <phrase><rfc2119>may</rfc2119> be</phrase> raised <errorref class="DC"
               code="0004"/> if <code>$source</code> is not
            a valid <code>xs:anyURI</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>In some implementations, there might be a close relationship between <term>collections</term> (as retrieved
         by the <function>fn:collection</function> function), and <term>URI collections</term> (as retrieved by this function).
         For example, a collection might return XML documents, and the corresponding URI collection might return
         the URIs of those documents. However, this specification does not impose such a close relationship. For example, there
         may be collection URIs accepted by one of the two functions and not by the other; a collection might contain
         items that do not have any URI; or a URI collection might contain URIs that cannot be dereferenced to return any 
         resource.</p>


         <p>In the case where <function>fn:uri-collection</function> returns the URIs of resources that
            could also be retrieved directly using <function>fn:collection</function>, there are several reasons why it 
            might be appropriate to use this function in preference
            to the <function>fn:collection</function> function. For example:</p>

         <ulist>
            <item>
               <p>It allows different URIs for different kinds of resource to be dereferenced in
                  different ways: for
                  example, the returned URIs might be referenced using the
                     <function>fn:unparsed-text</function> function rather than the <function>fn:doc</function>
                  function.</p>
            </item>
            <item>
               <p>In XSLT 3.0 it allows the documents in a collection to be processed in streaming mode using the
                     <code>xsl:stream</code> instruction.</p>
            </item>
            <item>
               <p>It allows recovery from failures to read, parse, or validate individual documents,
                  by calling the <function>fn:doc</function> (or other dereferencing) function within the scope of try/catch.</p>
            </item>
            <item>
               <p>It allows selection of which documents to read based on their URI, for example
                  they can be filtered to select those whose URIs end in <code>.xml</code>, or those
                  that use the <code>https</code> scheme.</p>
            </item>
            <item>
               <p>An application might choose to limit the number of URIs processed in a single run,
                  for example it might process only the first 50 URIs in the collection; or it might
                  present the URIs to the user and allow the user to select which of them need to be
                  further processed.</p>
            </item>
            <item>
               <p>It allows the URIs to be modified before they are dereferenced, for example by
                  adding or removing query parameters, or by redirecting the request to a local
                  cache or to a mirror site.</p>
            </item>
         </ulist>

         <p>For some of these use cases, this assumes that the cost of calling
               <function>fn:collection</function> might be significant (for example, it might involving
            retrieving all the documents in the collection over the network and parsing them). This
            will not necessarily be true of all implementations.</p>






      </fos:notes>
   </fos:function>
   <fos:function name="unparsed-text" prefix="fn">
      <fos:signatures>
         <fos:proto name="unparsed-text" return-type="xs:string?">
            <fos:arg name="source" type="xs:string?"/>
            <fos:arg name="options" type="(xs:string | map(*))?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>The <function>fn:unparsed-text</function> function reads an external resource (for example, a
            file) and returns a string representation of the resource.</p>
      </fos:summary>
      <fos:rules>
         <p>The <code>$source</code> argument <rfc2119>must</rfc2119> be a string in the form of a URI
            reference, which <rfc2119>must</rfc2119> contain no fragment identifier, and
               <rfc2119>must</rfc2119> identify a resource for which a string representation is
            available.</p>
         <p>If <code>$source</code> is a relative URI reference, it is resolved relative to the value
            of the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> property 
            from the dynamic context of the caller. The resulting absolute URI is
            promoted to an <code>xs:string</code>.</p>
         
         <p>The <code>$options</code> argument, for backwards compatibility reasons, may be supplied
         either as a map, or as a string. Supplying a value <code>$S</code> that is not a map
            is equivalent to supplying the map <code>{ "encoding": $S }</code>.
            After that substitution, the <termref def="option-parameter-conventions"/> apply.</p>
         
         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>
         
         <fos:options>
            <fos:option key="encoding">
               <fos:meaning>Defines the encoding of the resource, as described below.
               </fos:meaning>
               <fos:type>xs:string?</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="normalize-newlines">
               <fos:meaning>Determines whether CR and CRLF character sequences
                  are treated as equivalent to NL characters.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">No normalization of line endings takes place.
                  </fos:value>
                  <fos:value value="true">The character <char>U+000D</char>
                     and the character pair (<char>U+000D</char>, <char>U+000A</char>) are converted to the
                     single character <char>U+000A</char>.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="fallback">
               <fos:meaning>
                  If <code>$fallback</code> is true, any character that 
                  cannot be decoded or that is not a <termref def="dt-permitted-character"/>
                  is replaced by the Unicode replacement character
                  (<char>U+FFFD</char>).
               </fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
         </fos:options>
                
         <p>The way in which an absolute URI is dereferenced to obtain an external resource is 
            described in <xspecref spec="XP40" ref="id-security-resources"/>.</p>
         
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
         
         <p>If the <code>$source</code> argument is the empty sequence, the function
            returns the empty sequence.</p>
         <p>The <code>encoding</code> option, if non-empty, is the name of an encoding.
            The values for this option follow the same rules as for the <code>encoding</code> attribute
            in an XML declaration. The values which an implementation is <rfc2119>required</rfc2119>
            to recognize are <code>UTF-8</code>, <code>UTF-16</code>, <code>UTF-16LE</code>,
            and <code>UTF-16BE</code> (in any upper/lower case combination).</p>

         <p>The effective encoding is chosen as follows:</p>
         <olist>
            <item>
               <p>external encoding information if available; otherwise</p>
            </item>
            <item>
               <p>the encoding recognized as specified in <bibref ref="xml"/> if the media type
                  of the resource is <code>text/xml</code> or <code>application/xml</code>
                  (see <bibref ref="rfc2376"/>), or if it matches the conventions
                  <code>text/*+xml</code> or <code>application/*+xml</code>
                  (see <bibref ref="rfc7303"/> and/or its successors); otherwise</p>
            </item>
            <item>
               <p>the value of the <code>encoding</code> option if present; otherwise</p>
            </item>
            <item>
               <p>the encoding inferred from the initial octets of the resource,
               or from <termref def="implementation-defined"/> heuristics
               as defined by the rules of the <function>bin:infer-encoding</function>
               function.</p>
            </item>
         </olist>

         
         <note><p>Encoding names are compared without regard to case.</p></note>
         <p>If the input (as decoded using the effective encoding) starts with a byte order mark,
            then the byte order mark is not included in the result.</p>

         <p>The result of the function is a string containing the string representation of the
            resource retrieved using the URI, decoded according to the effective encoding.</p>
         
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="UT" code="1170"
               /> if the <code>$source</code> argument
            contains a fragment identifier, <phrase>or if it cannot be resolved
            to an absolute URI (for example, because the base-URI property in the static context is absent), 
            </phrase>or if it cannot be used to retrieve the string
            representation of a resource. </p>
         <p diff="chg" at="2023-06-12">A dynamic error is raised <errorref class="UT" code="1190"
            /> if the value of the
            <code>encoding</code> option is not a valid encoding name, if the
            processor does not support the specified encoding, if
            the string representation of the retrieved resource contains octets that cannot be
            decoded into Unicode <termref def="character">characters</termref> using the specified
            encoding, or if any resulting character is not a
            <termref def="dt-permitted-character">permitted character</termref>.</p>
         <p>A dynamic error is raised <errorref class="UT" code="1200"
            /> if the <code>encoding</code> option
            is absent and the processor cannot infer the
            encoding using external information and the actual encoding is not UTF-8.</p>
      </fos:errors>

      <fos:notes>
         <p>If it is appropriate to use a base URI other than the 
            <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> (for example,
            when resolving a relative URI reference read from a source document) then it is
            advisable to resolve the relative URI reference using the <function>fn:resolve-uri</function>
            function before passing it to the <function>fn:unparsed-text</function> function.</p>
         <p>There is no essential relationship between the sets of URIs accepted by the two
            functions <function>fn:unparsed-text</function> and <function>fn:doc</function> (a URI accepted by one
            may or may not be accepted by the other), and if a URI is accepted by both there is no
            essential relationship between the results (different resource representations are
            permitted by the architecture of the web).</p>
         <p>There are no constraints on the MIME type of the resource.</p>


         <p>The fact that the resolution of URIs is defined by a mapping in the dynamic context
            means that in effect, various aspects of the behavior of this function are <termref
               def="implementation-defined"
            >implementation-defined</termref>. Implementations may provide external configuration
            options that allow any aspect of the processing to be controlled by the user. In
            particular:</p>
         <ulist>
            <item>
               <p>The set of URI schemes that the implementation recognizes is
                  implementation-defined. Implementations may allow the mapping of URIs to resources
                  to be configured by the user, using mechanisms such as catalogs or user-written
                  URI handlers.</p>
            </item>
            <item>
               <p>The handling of media types is implementation-defined.</p>
            </item>
            <item>
               <p>Implementations may provide user options that relax the requirement for the function
               to return deterministic results.</p>
            </item>

            <item>
               <p>Implementations may provide user-defined error handling options that allow
                  processing to continue following an error in retrieving a resource, or in reading
                  its content. When errors have been handled in this way, the function may return a
                  fallback document provided by the error handler.</p>
            </item>
            
         </ulist>

         <p>The rules for determining the encoding are chosen for consistency with <bibref
               ref="xinclude"
            />. Files with an XML media type are treated specially because there
            are use cases for this function where the retrieved text is to be included as unparsed
            XML within a CDATA section of a containing document, and because processors are likely
            to be able to reuse the code that performs encoding detection for XML external
            entities.</p>
         <p>If the text file contains characters such as <code>&lt;</code> and <code>&amp;</code>,
            these will typically be output as <code>&amp;lt;</code> and <code>&amp;amp;</code> if
            the string is serialized as XML or HTML. If these characters actually represent markup
            (for example, if the text file contains HTML), then an XSLT stylesheet can attempt to
            write them as markup to the output file using the <code>disable-output-escaping</code>
            attribute of the <code>xsl:value-of</code> instruction. Note, however, that XSLT
            implementations are not required to support this feature.</p>
      </fos:notes>

      <fos:examples>
         <fos:example>
            <p>This XSLT example attempts to read a file containing “boilerplate” HTML and copy it
               directly to the serialized output file:</p>
            <eg xml:space="preserve"><![CDATA[<xsl:output method="html"/>

<xsl:template match="/">
  <xsl:value-of select="unparsed-text('header.html', 'iso-8859-1')"
                disable-output-escaping="yes"/>
  <xsl:apply-templates/>
  <xsl:value-of select="unparsed-text('footer.html', 'iso-8859-1')"
                disable-output-escaping="yes"/>
</xsl:template>
]]></eg>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1116" PR="1117" date="2024-05-21">
            <p>The <code>$options</code> parameter has been added.</p>
         </fos:change>
         <fos:change issue="414" PR="546" date="2023-07-25">
            <p>It is no longer automatically an error if the resource (after decoding) 
               contains a codepoint that is not valid in XML. Instead, the codepoint
            must be a <termref def="dt-permitted-character"/>. The set of permitted
            characters is <termref def="implementation-defined"/>, but it is
            <rfc2119>recommended</rfc2119> that all Unicode characters should 
               be accepted.</p>
         </fos:change>
         <fos:change issue="2221" PR="2249" date="2025-10-21">
            <p>The specification now describes in more detail how to determine the effective
               encoding value.</p>
         </fos:change>
         <fos:change issue="2460" PR="2510" date="2026-03-11">
            <p>A fallback option is now provided to address characters that cannot be
            decoded or are not permitted.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="unparsed-text-lines" prefix="fn">
      <fos:signatures>
         <fos:proto name="unparsed-text-lines" return-type="xs:string*">
            <fos:arg name="source" type="xs:string?"/>
            <fos:arg name="options" type="(xs:string | map(*))?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>The <function>fn:unparsed-text-lines</function> function reads an external resource (for
            example, a file) and returns its contents as a sequence of strings, one for each line of
            text in the string representation of the resource.</p>
      </fos:summary>
      <fos:rules>
         <p>The <code>unparsed-text-lines</code> function reads an external resource (for example, a
            file) and returns its string representation as a sequence of strings, separated at
            newline boundaries.</p>
         <p>The <code>$options</code> argument, for backwards compatibility reasons, may be supplied
         either as a map, or as a string. Supplying a value <code>$S</code> that is not a map
            is equivalent to supplying the map <code>{ "encoding": $S }</code>.
            After that substitution, the <termref def="option-parameter-conventions"/> apply.</p>
         
         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>
         
         <fos:options>
            <fos:option key="encoding">
               <fos:meaning>Defines the encoding of the resource, following the rules of <function>fn:unparsed-text</function>.
               </fos:meaning>
               <fos:type>xs:string?</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="fallback">
               <fos:meaning>
                  If <code>$fallback</code> is true, any character that 
                  cannot be decoded or that is not a <termref def="dt-permitted-character"/>
                  is replaced by the Unicode replacement character
                  (<char>U+FFFD</char>).
               </fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
         </fos:options>
        
         <p>The result of the function is the same as the result of the expression:</p>
         
         <eg>let $text := unparsed-text($source, map:put($options, 'normalize-newlines', true()))
let $lines := tokenize($text, '\n')
return $lines[not(position() = last() and . = '')]
         </eg>
 
         <p>The result is thus a sequence of strings containing the text of the resource retrieved
            using the URI, each string representing one line of text. Lines may be delimited by
            any of the character sequences <char>U+000A</char>, <char>U+000D</char>, or <char>U+000D</char>
            followed by <char>U+000A</char>.
            Line ending characters are not
            included in the returned strings. If there are two adjacent newline sequences, a
            zero-length string will be returned to represent the empty line; but if the external
            resource ends with a newline sequence, the result will be as if this final
            line ending were not present.</p>
         
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
      </fos:rules>
      <fos:errors>
         <p>Error conditions are the same as for the <function>fn:unparsed-text</function> function.</p>

      </fos:errors>

      <fos:notes>
         <p>See the notes for <function>fn:unparsed-text</function>.</p>
      </fos:notes>
      <fos:changes>
         <fos:change issue="1116 1278" PR="1117 1279" date="2024-05-21">
            <p>The <code>$options</code> parameter has been added.</p>
         </fos:change>
         <fos:change issue="2460" PR="2510" date="2026-03-11">
            <p>A fallback option is now provided to address characters that cannot be
            decoded or are not permitted.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="unparsed-text-available" prefix="fn">
      <fos:signatures>
         <fos:proto name="unparsed-text-available" return-type="xs:boolean">
            <fos:arg name="source" type="xs:string?"/>
            <fos:arg name="options" type="(xs:string | map(*))?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Allows an application to determine
            whether a call on <function>fn:unparsed-text</function> with particular arguments 
            would succeed.</p>
      </fos:summary>
      <fos:rules>
         <p>The <function>fn:unparsed-text-available</function> function determines whether a call
            on the <function>fn:unparsed-text</function> function with identical arguments would
            return a string.</p>
         <p>If the first argument is the empty sequence, the function returns <code>false</code>. </p>
         <p>In other cases, the function returns <code>true</code> if a call on
               <function>fn:unparsed-text</function> or <function>fn:unparsed-text-lines</function>
            with the same arguments would succeed, and
            <code>false</code> if a call on <function>fn:unparsed-text</function> 
            or <function>fn:unparsed-text-lines</function> with the same arguments would
            fail with a non-recoverable dynamic error.</p>
         
         <p>The functions <function>fn:unparsed-text</function> and
               <function>fn:unparsed-text-available</function> have the same requirement for
               <termref
               def="dt-deterministic"
               >determinism</termref> as the functions
               <function>fn:doc</function> and <function>fn:doc-available</function>. This means that unless the
            user has explicitly stated a requirement for a reduced level of determinism, either of
            these functions if called twice with the same arguments during the course of a
            transformation <rfc2119>must</rfc2119> return the same results each time; moreover, the
            results of a call on <function>fn:unparsed-text-available</function>
            <rfc2119>must</rfc2119> be consistent with the results of a subsequent call on
               <code>unparsed-text</code> with the same arguments.</p>
         
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
         
      </fos:rules>
      <fos:notes>
         <p>This function was introduced before XQuery and XSLT allowed errors to be caught;
            with current versions of these host languages, catching an error from
            <function>fn:unparsed-text</function> may provide a better alternative.</p>
         <p>The specification requires that the <function>fn:unparsed-text-available</function> function should
            actually attempt to read the resource identified by the URI, and check that it is
            correctly encoded and contains no characters that are invalid in XML. Implementations
            may avoid the cost of repeating these checks for example by caching the validated
            contents of the resource, to anticipate a subsequent call on the
               <function>fn:unparsed-text</function> or <function>fn:unparsed-text-lines</function>
            function. Alternatively, implementations may be able to rewrite an expression such as
               <code>if (unparsed-text-available(A)) then unparsed-text(A) else ...</code> to
            generate a single call internally.</p>
         <p>Since the function <function>fn:unparsed-text-lines</function> succeeds or fails under
            exactly the same circumstances as <function>fn:unparsed-text</function>, the
               <function>fn:unparsed-text-available</function> function may equally be used to test
            whether a call on <function>fn:unparsed-text-lines</function> would succeed.</p>
         
         

      </fos:notes>
      <fos:changes>
         <fos:change issue="1116" PR="1117" date="2024-05-21">
            <p>The <code>$options</code> parameter has been added.</p>
         </fos:change>
      </fos:changes>

   </fos:function>
   
   
   <fos:function name="unparsed-binary" prefix="fn">
      <fos:signatures>
         <fos:proto name="unparsed-binary" return-type="xs:base64Binary?">
            <fos:arg name="source" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>The <code>fn:unparsed-binary</code> function reads an external resource (for example, a
            file) and returns its contents in binary.</p>
      </fos:summary>
      <fos:rules>
         <p>The <code>$source</code> argument <rfc2119>must</rfc2119> be a string in the form of a URI
            reference, which <rfc2119>must</rfc2119> contain no fragment identifier, and
               <rfc2119>must</rfc2119> identify a resource for which a binary representation is
            available.</p>
         
         <p>If <code>$source</code> is a relative URI reference, it is resolved relative to the value
            of the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> property 
            from the dynamic context of the caller. The resulting absolute URI is
            promoted to an <code>xs:string</code>.</p>
         
         
         

                
         <p>The mapping of URIs to the binary representation of a resource is the mapping defined in
            the <xtermref
               spec="XP40" ref="dt-available-binary-resources"/> component of the dynamic context.</p>
         <p>If the <code>$source</code> argument is the empty sequence, the function
            returns the empty sequence.</p>
         
         <p>The result of the function is an atomic item of type <code>xs:base64Binary</code> 
            containing the binary representation of the
            resource retrieved using the URI.</p>
         
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="UT" code="1170"
               /> if the <code>$source</code> argument
            contains a fragment identifier, <phrase>or if it cannot be resolved
            to an absolute URI (for example, because the base-URI property in the static context is absent), 
            </phrase>or if it cannot be used to retrieve the binary
            representation of a resource. </p>
         
      </fos:errors>

      <fos:notes>
         <p>If it is appropriate to use a base URI other than the 
            <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> (for example,
            when resolving a relative URI reference read from a source document) then it is
            advisable to resolve the relative URI reference using the <code>fn:resolve-uri</code>
            function before passing it to the <code>fn:unparsed-text</code> function.</p>
         <p>There is no essential relationship between the sets of URIs accepted by the 
            function <code>fn:unparsed-binary</code> and other functions such as
            <code>fn:doc</code> and <code>fn:unparsed-text</code>  (a URI accepted by one
            may or may not be accepted by the others), and if a URI is accepted by more than 
            one of these functions then there is no
            essential relationship between the results (different resource representations are
            permitted by the architecture of the web).</p>
         <p>There are no constraints on the MIME type of the resource.</p>


         <p>The fact that the resolution of URIs is defined by a mapping in the dynamic context
            means that in effect, various aspects of the behavior of this function are <termref
               def="implementation-defined"
            >implementation-defined</termref>. Implementations may provide external configuration
            options that allow any aspect of the processing to be controlled by the user. In
            particular:</p>
         <ulist>
            <item>
               <p>The set of URI schemes that the implementation recognizes is
                  implementation-defined. Implementations may allow the mapping of URIs to resources
                  to be configured by the user, using mechanisms such as catalogs or user-written
                  URI handlers.</p>
            </item>
            <item>
               <p>The handling of media types is implementation-defined.</p>
            </item>
            <item>
               <p>Implementations may provide user options that relax the requirement for the function
               to return deterministic results.</p>
            </item>

            <item>
               <p>Implementations may provide user-defined error handling options that allow
                  processing to continue following an error in retrieving a resource, or in reading
                  its content. When errors have been handled in this way, the function may return a
                  fallback document provided by the error handler.</p>
            </item>
            
         </ulist>

         
         <p>There is no function (analogous to <code>fn:doc-available</code> or <code>fn:unparsed-text-available</code>)
            to determine whether a suitable resource is available. In XQuery and XSLT, try/catch
            constructs are available to catch the error.</p>
         <p>The choice of <code>xs:base64Binary</code> rather than <code>xs:hexBinary</code> for the
            result is arbitrary. The two types have the same value space and are interchangeable for nearly
            all purposes, the notable exception being conversion to <code>xs:string</code>.</p>
         <p>A comprehensive set of functions for manipulating binary data is available in the
            EXPath binary module: see <bibref ref="expath"/>. In addition, the EXPath file module
            provides a function <code>file:read-binary</code> with similar functionality to
            <code>fn:unparsed-binary</code>, the notable differences being (a) that it takes
            a file name rather than a URI, and (b) that it is defined to be nondeterministic.
          </p>
      </fos:notes>




      <fos:examples>
         <fos:example>
            <p>The following XQuery, adapted from an example in the EXPath binary module <bibref ref="expath"/>,
               reads a JPEG image and determines its size in pixels:</p>
            
            <eg><![CDATA[declare namespace bin = "http://expath.org/ns/binary";
let $content := fn:unparsed-binary("image.jpeg")
let $int16-at := bin:unpack-unsigned-integer(
                    $content, ?, 2, 'most-significant-first')
let $loc := bin:find($content, 0, bin:hex('FFC0'))
return { "width": $int16-at($loc + 5),
         "height": $int16-at($loc + 7) }]]></eg>
            
            <p>The example assumes that the functions in the EXPath binary module are available.</p>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="557" PR="1587" date="2024-11-18">
            <p>New in 4.0</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   
   
   <fos:function name="environment-variable" prefix="fn">
      <fos:signatures>
         <fos:proto name="environment-variable" return-type="xs:string?">
            <fos:arg name="name" type="xs:string"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="environment-variables">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value of a system environment variable, if it exists.</p>
      </fos:summary>
      <fos:rules>
         <p>The set of available <xtermref spec="XP40" ref="dt-environment-variables"
               >environment
               variables</xtermref> is a set of (name, value) pairs forming part of the dynamic
            context, in which the name is unique within the set of pairs. The name and value are
            arbitrary strings.</p>
         <p>If the <code>$name</code> argument matches the name of one of these pairs, the function
            returns the corresponding value.</p>
         <p>If there is no environment variable with a matching name, the function returns the empty
            sequence.</p>
         <p>The collation used for matching names is <termref def="implementation-defined"
               >implementation-defined</termref>, but
            must be the same as the collation used to ensure that the names of all environment
            variables are unique.</p>
         <p>The function is <termref def="dt-deterministic"
               >deterministic</termref>, which means
            that if it is called several times within the same <termref
               def="execution-scope"
            >execution scope</termref>, with the same arguments, it must return the same
            result.</p>
        
      </fos:rules>
      <fos:notes>
         <p>On many platforms, the term “environment variable” has a natural meaning in terms of
            facilities provided by the operating system. This interpretation of the concept does not
            exclude other interpretations, such as a mapping to a set of configuration parameters in
            a database system.</p>
         <p>Environment variable names are usually case sensitive. Names are usually of the form
               <code>(letter|_) (letter|_|digit)*</code>, but this varies by platform.</p>
         <p>On some platforms, there may sometimes be multiple environment variables with the same
            name; in this case, it is implementation-dependent as to which is returned; see for
            example <bibref
               ref="POSIX.1-2008"
               /> (Chapter 8, Environment Variables). Implementations
               <rfc2119>may</rfc2119> use prefixes or other naming conventions to disambiguate the
            names.</p>
         <p>The requirement to ensure that the function is deterministic means in practice that the
            implementation must make a snapshot of the environment variables at some time during
            execution, and return values obtained from this snapshot, rather than using live values
            that are subject to change at any time.</p>
         <p>Operating system environment variables may be associated with a particular process,
            while queries and stylesheets may execute across multiple processes (or multiple
            machines). In such circumstances implementations <rfc2119>may</rfc2119> choose to
            provide access to the environment variables associated with the process in which the
            query or stylesheet processing was initiated.</p>
         <p>Security advice: <xtermref spec="XP40" ref="dt-untrusted">Untrusted</xtermref> 
            applications should not be permitted unrestricted
            access to environment variables. For example, the name of the account under which a
            query is running may be useful information to a would-be intruder. An implementation may
            therefore choose to restrict access to the environment, or may provide a facility to
            make <function>fn:environment-variable</function> always return the empty sequence.</p>

      </fos:notes>
   </fos:function>
   <fos:function name="available-environment-variables" prefix="fn">
      <fos:signatures>
         <fos:proto name="available-environment-variables" return-type="xs:string*"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="environment-variables">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a list of environment variable names that are suitable for passing to
               <function>fn:environment-variable</function>, as a (possibly empty) sequence of strings.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence of strings, being the names of the environment variables
            in the dynamic context in some <termref
               def="implementation-dependent">implementation-dependent</termref> order.</p>
         <p>The function is <termref def="dt-deterministic"
            >deterministic</termref>: that is, the
            set of available environment variables does not vary during evaluation.</p>
      </fos:rules>
      <fos:notes>
         <p>The function returns a list of strings, containing no duplicates.</p>
         <p>It is intended that the strings in this list should be suitable for passing to
               <function>fn:environment-variable</function>.</p>

         <p>See also the note on security under the definition of the
               <function>fn:environment-variable</function> function. If access to environment variables has
            been disabled, <function>fn:available-environment-variables</function> always returns the empty
            sequence.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="generate-id" prefix="fn">
      <fos:signatures>
         <fos:proto name="generate-id" return-type="xs:string">
            <fos:arg name="node" type="gnode()?" usage="inspection" default="."/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="0">
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
      </fos:properties>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>This function returns a string that uniquely identifies a given GNode. </p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$node</code> is the empty sequence, the result is the zero-length string.</p>
         <p>In other cases, the function returns a string that uniquely identifies a given node.
            <phrase>More formally, it is guaranteed that within a single
             <termref
                  def="execution-scope"
                  >execution scope</termref>, 
               <code>fn:codepoint-equal(fn:generate-id($N), fn:generate-id($M))</code> returns <code>true</code> 
               if and only if <code>($M is $N)</code> returns <code>true</code>.</phrase></p>

         <p>The returned identifier <rfc2119>must</rfc2119> consist of ASCII alphanumeric characters
            and <rfc2119>must</rfc2119> start with an alphabetic character. Thus, the string is
            syntactically an XML name.</p>

      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/></p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type
               <code>gnode()?</code>, type error <xerrorref spec="XP" class="TY" code="0004" type="type"/>.</p>
            </item>
         </ulist>

      </fos:errors>
      <fos:notes>
         <p>An implementation is free to generate an identifier in any convenient way provided that
            it always generates the same identifier for the same GNode and that different identifiers
            are always generated from different GNodes. An implementation is under no obligation to
            generate the same identifiers each time a document is transformed or queried.</p>
         <p>There is no guarantee that a generated unique identifier will be distinct from any
            unique IDs specified in the source document.</p>
         <p>There is no inverse to this function; it is not directly possible to find the GNode with
            a given generated ID. Of course, it is possible to search a given sequence of GNodes
            using an expression such as <code>$nodes[generate-id()=$id]</code>.</p>
         <p>It is advisable, but not required, for implementations to generate IDs that are distinct
            even when compared using a case-blind collation.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>The primary use case for this function is to generate hyperlinks. For example, when
               generating HTML, an anchor for a given section <code>$sect</code> can be generated by
               writing (in either XSLT or XQuery):</p>
            <p>
               <code><![CDATA[<a name="{ generate-id($sect) }"/>]]></code>
            </p>
            <p>and a link to that section can then be produced with code such as:</p>
            <p>
               <code><![CDATA[see <a href="#{ generate-id($sect) }">here</a>]]></code>
            </p>
            <p>Note that anchors generated in this way will not necessarily be the same each time a
               document is republished.</p>

         </fos:example>
         <fos:example>
            <p>Since the keys in a map must be atomic items, it is possible to use generated IDs
               as surrogates for nodes when constructing a map. For example, in some implementations,
               testing whether a node <code>$N</code> is a member of a large node-set <code>$S</code>
               using the expression <code>exists($N intersect $S)</code> may be expensive; there
               may then be performance benefits in creating a map:</p>
            <p>
               <code>let $SMap := map:merge($S ! { generate-id(.) : . })</code>
            </p>
            <p>and then testing for membership of the node-set using:</p>
            <p>
               <code>map:contains($SMap, generate-id($N))</code>
            </p>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   
   <fos:function name="parse-xml" prefix="fn">
      <fos:signatures>
         <fos:proto name="parse-xml" return-type="document-node(*)?">
            <fos:arg name="value" type="(xs:string | xs:hexBinary | xs:base64Binary)?" example="'&lt;a/&gt;'"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>This function takes as input an XML document, and returns the
            document node at the root of an XDM tree representing the parsed document.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>

         <p>In other cases, <code>$value</code> is expected to contain an XML document supplied
            either as a string or a binary value. If it is supplied as a binary value, an optional
            byte order mark or XML declaration may contain the input encoding, and the input will be
            processed like a resource retrieved by the <function>fn:doc</function> function.
            Otherwise, if the input is a string, any byte order mark as well as the encoding specified
            in an optional XML declaration <rfc2119>should</rfc2119> be ignored.</p>

         <p>The <code>$options</code> argument defines the detailed behavior of the
         function. The <termref def="option-parameter-conventions"/> apply. The options available
         are as follows:</p>
         
         <fos:options>
            <fos:option key="base-uri">
               <fos:meaning>Determines the base URI. This is used both as the base URI 
                  used by the XML parser to resolve relative entity references within the document, 
                  and as the base URI of the document node that is returned. It defaults
                  to the static base URI of the function call.</fos:meaning>
               <fos:type>xs:anyURI</fos:type>
               <fos:default>static-base-uri()</fos:default>
            </fos:option>
            <fos:option key="dtd-validation">
               <fos:meaning>Determines whether DTD validation takes place.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">The input is parsed using a validating XML parser.
                  The input must contain a <code>DOCTYPE</code> declaration to identify
                  the DTD to be used for validation. The DTD may be internal or external.
                  </fos:value>
                  <fos:value value="false">DTD validation does not take place. However, if a
                     <code>DOCTYPE</code> declaration is present, then it is read, for example
                     to perform entity expansion.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="strip-space">
               <fos:meaning>Determines whether whitespace-only text nodes are removed
                  from the resulting document. (Note: in XSLT, the <code>xsl:strip-space</code>
                  and <code>xsl:preserve-space</code> declarations are ignored.)</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">All whitespace-only text nodes are stripped,
                  unless either (a) they are within the scope of the attribute <code>xml:space="preserve"</code>,
                  or (b) XSD validation identifies that the parent element has a simple type or a complex
                  type with simple content.
                  </fos:value>
                  <fos:value value="false">All whitespace-only text nodes are preserved,
                  unless either (a) DTD validation marks them as ignorable, or (b) XSD validation recognizes
                  the containing element as having element-only or empty content.
                  </fos:value>
               </fos:values>
            </fos:option>
             <fos:option key="trusted">
               <fos:meaning>Indicates whether processing the supplied document may cause 
                  external resources to be fetched (including, for example, external entities, an external DTD,
                  or documents referenced using <code>xsi:schemaLocation</code> or
                  XInclude elements).</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false()</fos:default>
               <fos:values>
                  <fos:value value="true">The document may include references to external
                     resources.
                  </fos:value>
                  <fos:value value="false">The document must not include references to 
                     external resources unless access to these resources has been explicitly
                     enabled.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="xinclude">
               <fos:meaning>Determines whether any <code>xi:include</code> elements in the input
                  are to be processed using an XInclude processor.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">Any <code>xi:include</code> elements are expanded. If there are
                     <code>xi:include</code> elements and no XInclude processor is available then 
                     a dynamic error is raised.
                  </fos:value>
                  <fos:value value="false">Any <code>xi:include</code> elements are handled as
                     ordinary elements without expansion.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="xsd-validation">
               <fos:meaning>Determines whether XSD validation takes place, using the
                  schema definitions present in the static context. The effect of requesting
               validation is the same as invoking the <function>parse-xml</function> function without
               validation, and then applying an XQuery <code>validate</code> expression to the result,
               with corresponding options.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"skip"</fos:default>
               <fos:values>
                  <fos:value value="strict">Strict XSD validation takes place</fos:value>
                  <fos:value value="lax">Lax XSD validation takes place</fos:value>
                  <fos:value value="skip">No XSD validation takes place</fos:value>
                  <fos:value value="type Q{uri}local">XSD validation takes place against the
                  schema-defined type, present in the static context, that has the given URI
                  and local name.</fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="use-xsi-schema-location">
               <fos:meaning>When XSD validation takes place, determines whether
                  schema components referenced using <code>xsi:schemaLocation</code> or <code>xsi:noNamespaceSchemaLocation</code>
                  attributes within the source document are to be used. The option is ignored
                  if XSD validation does not take place.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">XSD validation uses the schema components referenced 
                  using <code>xsi:schemaLocation</code> or <code>xsi:noNamespaceSchemaLocation</code>
                  attributes in addition to the schema components present in the static context;
                  these components must be compatible as described in <xspecref spec="DM40" ref="schema-consistency"/>.</fos:value>
                  <fos:value value="false">Any <code>xsi:schemaLocation</code> and <code>xsi:noNamespaceSchemaLocation</code>
                  attributes in the document are ignored.</fos:value>
                 
               </fos:values>
            </fos:option>
         </fos:options>
         
         
         <p>Except to the extent defined by these options, the precise process used 
            to construct the XDM instance is <termref
               def="implementation-defined"
            >implementation-defined</termref>. In particular, it is implementation-defined whether an XML
            1.0 or XML 1.1 parser is used.</p>
         
         <p>The document URI of the returned node is <xtermref ref="dt-absent" spec="DM40">absent</xtermref>.</p>
         <p>The function is <emph>not</emph>
            <termref def="dt-deterministic"
               >deterministic</termref>: that is, if the function is called
            twice with the same arguments, it is <termref
               def="implementation-dependent"
            >implementation-dependent</termref> whether the same node is returned on both
            occasions.</p>
         <p>Options set in <code>$options</code> may be supplemented or modified based on 
            configuration options defined externally using <termref def="implementation-defined"/> 
            mechanisms.</p>
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0006"
               /> if the content of
               <code>$value</code> is not a well-formed and namespace-well-formed XML document.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0007"
               /> if DTD validation is
            carried out and the content of <code>$value</code> is not valid against the relevant DTD.</p>
         <p>A dynamic error is raised <errorref class="DC" code="0008"
               /> if the value of the <code>xsd-validation</code> option is not one of the
            permitted values (for example, if the string that follows <code>"type"</code>
            is not a valid <code>EQName</code>, or if it does not identify a type that is present in the
            static context).</p>
         <p>A dynamic error is raised <errorref class="DC" code="0009"
               /> if the value of the <code>xsd-validation</code> option is set to anything
            other than <code>skip</code> when the processor is not schema-aware. (XSLT 4.0
         and XQuery 4.0 define schema-awareness as an optional feature; other host languages
         may set their own rules.)</p>
         <p>A dynamic error is raised <errorref class="DC" code="0013"
               /> if processor does not have
            access to an XML parser supporting the requested options, for example the ability
            to perform DTD validation or XInclude processing or to prevent access to external entities.</p>
         
         <p>A dynamic error is raised <errorref class="DC" code="0014"
               /> if XSD validation is
            carried out and the content of <code>$value</code> is not valid against the relevant XSD schema.</p>
      </fos:errors>
      <fos:notes>
         <p>Since the XML document is presented to the parser as a string, rather than as a sequence
            of octets, the encoding specified within the XML declaration has no meaning. If the XML
            parser accepts input only in the form of a sequence of octets, then the processor must
            ensure that the string is encoded as octets in a way that is consistent with rules used
            by the XML parser to detect the encoding.</p>
         <p>A common use case for this function is to handle input documents that contain nested
            XML documents embedded within CDATA sections. Since the content of the CDATA section is
            exposed as text, the receiving query or stylesheet may pass this text to the
               <function>fn:parse-xml</function> function to create a tree representation of the nested
            document.</p>
         <p>Similarly, nested XML within comments is sometimes encountered, and lexical XML is
            sometimes returned by extension functions, for example, functions that access web
            services or read from databases.</p>
         <p>A use case arises in XSLT where there is a need to preprocess an input document before
            parsing. For example, an application might wish to edit the document to remove its
            DOCTYPE declaration. This can be done by reading the raw text using the
               <function>fn:unparsed-text</function> function, editing the resulting string, and then
            passing it to the <function>fn:parse-xml</function> function.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>fn:parse-xml("&lt;alpha>abcd&lt;/alpha>")</fos:expression>
               <fos:result narrative="true">A newly
               created document node, having an <code>alpha</code> element as its only child; the
                  <code>alpha</code> element in turn is the parent of a text node whose string value
               is <code>"abcd"</code>.</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>fn:parse-xml("&lt;alpha>&lt;beta> &lt;/beta>&lt;/alpha>", { "strip-space": true() })</fos:expression>
               <fos:result narrative="true">A newly
               created document node, having an <code>alpha</code> element as its only child; the
                  <code>alpha</code> element in turn is the parent of a <code>beta</code>
               element whose content is empty, as a result of whitespace stripping.</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="305" PR="1257" date="2024-06-11">
            <p>The <code>$options</code> parameter has been added.</p>
         </fos:change>
         <fos:change issue="1287" PR="1288" date="2024-06-25">
            <p>Additional error conditions have been defined.</p>
         </fos:change>
         <fos:change issue="1857 1860" PR="1879" date="2025-03-18">
            <p>Additional options to control DTD and XInclude processing have been added.</p>
         </fos:change>
         <fos:change issue="748" PR="2013" date="2025-05-20">
            <p>Support for binary input has been added.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="parse-xml-fragment" prefix="fn">
      <fos:signatures>
         <fos:proto name="parse-xml-fragment" return-type="document-node()?">
            <fos:arg name="value" type="(xs:string | xs:hexBinary | xs:base64Binary)?"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>This function takes as input an XML external entity represented as a string, and returns
            the document node at the root of an XDM tree representing the parsed document
            fragment.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>

         <p>If the input is supplied as a binary value, the function detects the encoding using the
            same rules as the <function>unparsed-text</function> function, except that the special
            handling of media types such as <code>text/xml</code> and <code>application/xml</code> may be skipped.
            Otherwise, if the input is a string, any byte order mark as well as the encoding specified
            in an optional XML declaration <rfc2119>should</rfc2119> be ignored.</p>
         
         <p>The input must be a namespace-well-formed external general parsed entity. More
            specifically, it must conform to the production rule <xnt
               spec="XML" ref="NT-extParsedEnt">extParsedEnt</xnt> in <bibref ref="xml"
               />, it must contain
            no entity references other than references to predefined entities, and it must satisfy
            all the rules of <bibref
               ref="xml-names"
            /> for namespace-well-formed documents with
            the exception that the rule requiring it to be a well-formed document is replaced by the
            rule requiring it to be a well-formed external general parsed entity.</p>
         
         <p>The input is parsed to form a sequence of nodes which become children of the new
            document node, in the same way as the content of any element is converted into a
            sequence of children for the resulting element node.</p>
         <p>The <code>$options</code> argument defines the detailed behavior of the
         function. The <termref def="option-parameter-conventions"/> apply. The options available
         are as follows:</p>
         
         <fos:options>
            <fos:option key="base-uri">
               <fos:meaning>Determines the base URI. This is used 
                  as the base URI of the document node that is returned. It defaults
                  to the static base URI of the function call.</fos:meaning>
               <fos:type>xs:anyURI</fos:type>
               <fos:default>static-base-uri()</fos:default>
            </fos:option>
            <fos:option key="strip-space">
               <fos:meaning>Determines whether whitespace-only text nodes are removed
                  from the resulting document.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">All whitespace-only text nodes are stripped,
                  unless they are within the scope of the attribute <code>xml:space="preserve"</code>.
                  </fos:value>
                  <fos:value value="false">All whitespace-only text nodes are preserved.
                  </fos:value>
               </fos:values>
            </fos:option>
           
         </fos:options>
         <p>DTD validation is <emph>not</emph> invoked (an external general parsed entity cannot contain
            a <code>DOCTYPE</code> declaration.</p>
         <p>Schema validation is <emph>not</emph> invoked, which means that the nodes in the
            returned document will all be untyped.</p>
         <p>XInclude processing is <emph>not</emph> invoked.</p>
         <p>Except as explicitly defined, the precise process used to construct the XDM instance is <termref
               def="implementation-defined"
            >implementation-defined</termref>. In particular, it is implementation-defined whether
            an XML 1.0 or XML 1.1 parser is used.</p>
         <p>The document URI of the returned node is <xtermref ref="dt-absent" spec="DM40">absent</xtermref>.</p>
         <p>The function is <emph>not</emph>
            <termref def="dt-deterministic"
               >deterministic</termref>: that is, if the function is called
            twice with the same arguments, it is <termref
               def="implementation-dependent"
            >implementation-dependent</termref> whether the same node is returned on both
            occasions.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0006"
               /> if the content of
               <code>$value</code> is not a well-formed external general parsed entity, if it contains
            entity references other than references to predefined entities, or if a document that
            incorporates this well-formed parsed entity would not be namespace-well-formed.</p>
      </fos:errors>
      <fos:notes>
         <p>See also the notes for the <function>fn:parse-xml</function> function.</p>
         <p>The main differences between <function>fn:parse-xml</function> and
               <function>fn:parse-xml-fragment</function> are that for <function>fn:parse-xml</function>, the
            children of the resulting document node must contain exactly one element node and no
            text nodes, wheras for <function>fn:parse-xml-fragment</function>, the resulting document node
            can have any number (including zero) of element and text nodes among its children. An
            additional difference is that the <emph>text declaration</emph> at the start of an
            external entity has slightly different syntax from the <emph>XML declaration</emph> at
            the start of a well-formed document.</p>
         <p>Note that all whitespace outside the <emph>text declaration</emph> is significant,
            including whitespace that precedes the first element node, unless the <code>strip-space</code>
            option is set.</p>
         <p>One use case for this function is to handle XML fragments stored in databases, which
            frequently allow zero-or-more top level element nodes. Another use case is to parse the
            contents of a <code>CDATA</code> section embedded within another XML document.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>parse-xml-fragment("&lt;alpha>abcd&lt;/alpha>&lt;beta>abcd&lt;/beta>")</fos:expression>
               <fos:result narrative="true">A newly created document node, having two elements named <code>alpha</code>
               and <code>beta</code> as its children; each of these elements in turn is the parent
               of a text node.</fos:result>
            </fos:test>
            
            <fos:test>
               <fos:expression>parse-xml-fragment("He was &lt;i>so&lt;/i> kind")</fos:expression>
               <fos:result narrative="true">A newly created document node having three children: a text node whose string
               value is <code>"He was "</code>, an element node named <code>i</code> having a child
               text node with string value <code>"so"</code>, and a text node whose string value is
                  <code>" kind"</code>.</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-xml-fragment("")</fos:expression>
               <fos:result narrative="true">A document node having
               no children.</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-xml-fragment(" ")</fos:expression>
               <fos:result narrative="true">A document node whose
               children comprise a single text node whose string value is a single space.</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-xml-fragment(" ", { "strip-space": true() })</fos:expression>
               <fos:result narrative="true">A document node having no children.</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-xml-fragment('&lt;?xml version="1.0" encoding="UTF-8"
                  standalone="yes"?>&lt;a/>')</fos:expression>
               <fos:error-result error-code="FODC0006"/>
               <fos:postamble>The <code>standalone</code> keyword is not permitted in the text
               declaration that appears at the start of an external general parsed entity. Thus, it
               is not the case that any input accepted by the <function>fn:parse-xml</function> function
               will also be accepted by the <function>fn:parse-xml-fragment</function>.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="305" PR="1257" date="2024-06-11">
            <p>The <code>$options</code> parameter has been added.</p>
         </fos:change>
         <fos:change issue="748" PR="2013" date="2025-05-20">
            <p>Support for binary input has been added.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
    <fos:function name="xsd-validator" prefix="fn">
      <fos:signatures>
         <fos:proto name="xsd-validator" return-type="function((document-node(*) | element() | attribute())?) as record(is-valid as xs:boolean, typed-node? as node(), error-details? as record(*)*)">
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Given an XSD schema, delivers a function item that can be invoked to validate a document, element, or attribute node
            against this schema.</p>
      </fos:summary>
      <fos:rules>
         <p>The <function>fn:xsd-validator</function> function returns a function item that can be used to validate a
        document node, element node, or attribute node with respect to a supplied schema.</p>
         
         <p>The details of how the schema is assembled, and the way it is used, are defined by the supplied <code>$options</code>.
            If the <code>$options</code> argument is empty, the effect is to use the schema components from the
            static context of the call on <function>fn:xsd-validator</function>. In the general case, however, the schema 
            used for validation may include components from any or all of the following:</p>
         
         <ulist>
            <item><p>The static context of the function call</p></item>
            <item><p>Explicitly supplied schema documents</p></item>
            <item><p>Schema components referenced in <code>xsi:schemaLocation</code> and <code>xsi:noNamespaceSchemaLocation</code>
            attributes within the instance document being validated.</p></item>
         </ulist>
         
         <p>More details of schema assembly appear below. 
            Taken together, the assembled components must constitute a valid schema.</p>
         
         
         
         <p>The function is designed to separate the process of assembling a schema from the process of performing instance
            validation. However, if the schema is to include components identified in
            <code>xsi:schemaLocation</code> and <code>xsi:noNamespaceSchemaLocation</code> attributes, then the process of
            assembling the schema cannot be completed until the instance document is available.</p>
         
         
         <p>The options recognized are as follows. The <termref def="option-parameter-conventions"/> apply.</p>
         
         
     
         
         
         <fos:options>
            <fos:option key="trusted">
               <fos:meaning>Indicates whether the validation process may cause 
                  external resources to be fetched (including, for example, documents 
                  referenced using the <code>schema-location</code>
                  property, or <code>xsi:schemaLocation</code> attributes within
                  the document being validated).</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false()</fos:default>
               <fos:values>
                  <fos:value value="true">The validation process may retrieve external
                     resources.
                  </fos:value>
                  <fos:value value="false">The validation process must not retrieve any 
                     external resources unless access to these resources has been explicitly
                     enabled.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="use-imported-schema">
               <fos:meaning>If true, the schema to be used for validation includes the schema components
                  available in the static context of the function call. If false, these components
                  are not used.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
            </fos:option>
            <fos:option key="schema">
               <fos:meaning>A list of XDM nodes containing XSD schema documents to be used
               for validation.</fos:meaning>
               <fos:type>element(xs:schema)*</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="target-namespace">
               <fos:meaning>A list of target namespaces identifying schema components to be used for
               validation. The way in which the processor locates schema components for the specified
               target namespaces is <termref def="implementation-defined"/>. A zero-length string denotes
               a no-namespace schema.</fos:meaning>
               <fos:type>xs:anyURI*</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="schema-location">
               <fos:meaning>A list of locations of XSD schema documents to be used to assemble a schema.
               Any relative URIs are resolved relative to the base URI of the function call.
               Access to the schema documents at these locations is allowed regardless of the value
               of the <code>trusted</code> option; access to indirectly referenced schema documents
               (for example, using <code>xs:include</code> is allowed only if the <code>trusted</code>
               option is set to <code>true</code>.</fos:meaning>
               <fos:type>xs:anyURI*</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="use-xsi-schema-location">
               <fos:meaning>If true, the schema to be used for validation includes any schema documents
               referenced by <code>xsi:schemaLocation</code> or <code>xsi:noNamespaceSchemaLocation</code>
               attributes in the instance document being validated. If false, these attributes are ignored.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="xsd-version">
               <fos:meaning>Set to the decimal value 1.0 or 1.1 to indicate which version of XSD is to be used.
               The default is <termref def="implementation-defined"/>. A processor may use a later version
               of XSD than the version requested, but must not use an earlier version.</fos:meaning>
               <fos:type>xs:decimal</fos:type>
            </fos:option>
            <fos:option key="validation-mode">
               <fos:meaning>The validation mode.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:values>
                  <fos:value value="strict">Validates the input using the element or attribute declaration for the
                  operand node. This element or attribute declaration must exist. This is the default
                  when the <code>type</code> option is absent.</fos:value>
                  <fos:value value="lax">Validates the input using the element or attribute declaration for the
                  operand node, if it exists.</fos:value>
                  <fos:value value="by-type">Validates the input using the supplied governing type. This is the
                  default when the <code>type</code> option is present.</fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="type">
               <fos:meaning>Establishes the governing type for validation. The type must be present
               in the assembled schema.</fos:meaning>
               <fos:type>xs:QName?</fos:type>
            </fos:option>
            <fos:option key="return-typed-node">
               <fos:meaning>If true, the result of the generated validation function, when validation
                  is successful, includes the property <code>typed-node</code> which contains a copy of the
                  target node augmented with type annotations and expanded default values. If false, the typed
                  node is not included in the result. If a node containing type annotations is to be returned,
                  then the schema used for validation must be compatible with all other schemas used within
                  the same query or stylesheet, as described in <xspecref spec="DM40" ref="schema-consistency"/>;
                  this is to ensure that the type annotations in the validated document have a consistent
                  interpretation.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
            </fos:option>
            <fos:option key="return-error-details">
               <fos:meaning>If true, the result of the generated validation function, when validation
                  is unsuccessful, includes detailed information about the nature of the validity errors
                  that were found. If false, the result only includes an indication that the document
                  was invalid. Note that setting the value to false means that validation can complete
                  as soon as the first error is found.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            
         </fos:options>
         
         <p>The first task of the function is to assemble a schema (that is, a collection of schema
         components). Schema components can come from a number of sources, and a schema can be assembled
         from more than one source, provided that the total collection of components comprises a valid schema:
         the main thing that will prevent this is if two sources contain conflicting definitions of the
         same named component.</p>
         
         <ulist>
            <item><p>The default is to use the in-scope schema components from the static context
            of the function call.</p></item>
            <item><p>Instead, or in addition, schema components may be loaded explictly
            for this validator. Supplementary schema components may be requested in a number of
            ways:</p>
            <ulist>
               <item><p>The <code>schema-location</code> option can specify one or more URIs that
               are interpreted as locations for source XSD schema documents, which are then
               assembled into a schema as described in the XSD specifications.</p></item>
               <item><p>The <code>schema</code> option can be used to identify one or more
               <code>xs:schema</code> element nodes holding source schema documents. This allows
               a schema to be constructed dynamically by the application, or to be held as
               a global variable in the source code of a query or stylesheet module.</p></item>
               <item><p>The <code>target-namespace</code> option can be used to supply
               the target namespaces of additional schema components that are known to the
               system or that are made available using some external mechanism. For example,
               the system might have built-in schemas for common namespaces such as
               the <code>xml</code>, <code>fn</code>, or <code>xlink</code> namespaces,
               or it might have a mechanism allowing schemas for a particular namespace
               to be registered using an external API or configuration mechanism.</p></item>
            </ulist></item>
            <item><p>The <code>use-xsi-schema-location</code> also allows the application
            to request that schema documents referenced from <code>xsi:schemaLocation</code>
            or <code>xsi:noNamespaceSchemaLocation</code> attributes should be included
            in the schema. By default these attributes are ignored.</p></item>
            <item><p>It is acceptable to assemble a schema from more than one of these
            sources. In addition, any of these sources can bring in additional components
            by the use of the XSD directives <code>xsl:include</code> and <code>xsl:import</code>.
            The important constraint is that the result should be a valid schema. This will only
            be the case if the sources used to assemble the schema are 
               <xtermref spec="DM40" ref="dt-schema-compatible">compatible</xtermref>
            with each other: see <xspecref spec="DM40" ref="schema-consistency"/>.</p></item>
            <item><p>The XSD specification allows a schema to be used for validation even when 
             it contains unresolved
             references to absent schema components. It is <termref def="implementation-defined"/> whether
             this function allows the schema to be incomplete in this way. For example,
            some processors might allow validation using a schema in which an element declaration
            contains a reference to a type declaration that is not present in the schema, provided
            that the element declaration is never needed in the course of a particular validation
            episode.</p></item>
         </ulist>
         
         <p>Having assembled a schema, the next task is to validate a supplied node (and the subtree
            rooted at that node).</p>
         
         <note><p>This description is a deliberate simplification. If the <code>use-xsi-schema-location</code>
         option is <code>true</code>, then assembly of the schema is not completed until the instance document
         is available, and in practice overlaps with the validation process.</p></note>
         
         <p>The <function>xsd-validator</function> function returns a function item (call it <var>V</var>)
         with the following characteristics:</p>
         
         <ulist>
            <item><p><var>V</var> has an arity of one. Call the value of the supplied argument
               <code>$target</code>. The required type of <code>$target</code>
            is <code>(document-node(*) | element() | attribute())?</code>: 
               that is, it accepts either a well-formed
            document node, or an element node, or an attribute node, or the empty sequence.</p></item> 
            
            <item><p>If the argument is the empty sequence
            then the result of <var>V</var> is also the empty sequence.</p></item>
            
            <item><p>In other cases, the result of a call on <var>V</var> is a record 
               containing the following fields:</p>
            
               <ulist>
                  <item><p><code>is-valid as xs:boolean</code>. This field is always present, and indicates
                  whether the supplied <code>$target</code> node was found to be valid against the schema.
                  The value is <code>true</code> if either (a) the validation outcome was <code>valid</code>, or
                  (b) lax validation was requested and the validation outcome was <code>notKnown</code>.
                  In other cases it is <code>false</code>.</p></item>
                  
                  <item><p><code>typed-node as (document-node(*) | element() | attribute())</code>. 
                     This field is present
                  only when (a) the option <code>return-typed-node</code> was set (explicitly or implicitly)
                  to <code>true</code>, and (b) the value of the <code>is-valid</code> field is <code>true</code>. 
                     It represents the root of a tree that is a deep copy of the input tree, 
                     augmented with type annotations and default values.</p></item>
                  
                  <item><p><code>error-details as map(*)*</code>. This field is present only when (a) the option
                  <code>return-error-details</code> was set 
                  to <code>true</code>, and (b) the supplied document was found to be invalid. The value is a sequence
                  of maps, each containing details of one invalidity that was found. The precise details of the
                  invalidities are <termref def="implementation-defined"/>, but they <rfc2119>may</rfc2119> include 
                  the following fields, if the information is available:</p>
                  
                  <ulist>
                     <item><p><code>message</code>. A string containing the text of an error message, intended
                     for a human reader.</p></item>
                     <item><p><code>rule</code>. A reference to the rule in the XSD specification that was violated.
                     This is a string comprising four parts separated by the character <char>U+007C</char>:</p>
                     <ulist>
                        <item><p>"1.0" or "1.1" indicating whether the reference is to the XSD 1.0 or 1.1 specification.</p></item>
                        <item><p>"1" or "2" indicating whether the reference is to part 1 or part 2 of the specification.</p></item>
                        <item><p>The name of the validation rule (for example "Datatype Valid").</p></item>
                        <item><p>The clause number within that validation rule (for example "2.3").</p></item>
                     </ulist>
                        <p>For example, if an attribute is declared to be of type <code>xs:integer</code>, but the
                        actual value is not in the lexical space of <code>xs:integer</code>, the value of <code>rule</code>
                        might be <code>"1.1|2|Datatype Valid|2.1"</code>.</p>
                     </item>
                     <item><p><code>node</code>. The node that was found to be invalid. Note that when a containing element 
                        <var>C</var> is invalid because a child element <var>D</var> is not allowed by its content
                        model, the invalid node is <var>C</var>, not <var>D</var>.</p></item>
                     <item><p><code>error-node</code>. The node whose presence led to detection of the invalidity. In the
                     above example, this would be <var>D</var>.</p></item>
                     <item><p><code>error-uri</code>. The URI of the XML entity in which the error was detected.</p></item>
                     <item><p><code>line-number</code>. The line number where the error was detected, within its external entity.</p></item>
                     <item><p><code>column-number</code>. The column number where the error was detected, within the error line number.</p></item>
                  </ulist>
                  
                  
                  </item>
               </ulist>
            </item>
            <item>
               <p>The validation is performed as described in <specref ref="xsd-validation"/>, with
               the assembled schema as the effective schema and <code>$target</code> as the operand node.</p>
            </item>
            <item>
               <p>If the <code>use-xsi-schema-location</code> option is <code>true</code> and a failure
               occurs processing an <code>xsi:schemaLocation</code> or <code>xsi:noNamespaceSchemaLocation</code>
               attribute (for example, because a schema document cannot be retrieved, or because the referenced
               schema document is invalid, or because it is incompatible with other schema components) 
               this is treated as an invalidity, not as a dynamic error:
               <var>V</var> returns successfully with <code>is-valid</code> set to <code>false</code>.</p>
            </item>
            <item>
               <p>The function <var>V</var> may fail with a dynamic error if it is not possible to determine whether or not the
               instance document is valid. This may happen, for example, if processor-defined limits are exceeded.</p>
            </item>
         </ulist>

      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0009"
               /> if the processor is not schema-aware, or if no schema processor with the required capabilities (such as XSD 1.1 support)
         is available.</p>
         
         <p>A dynamic error is raised <errorref class="DC" code="0015"
               /> if it is not possible to assemble a valid and consistent schema.</p>
         

     
      </fos:errors>
       <fos:notes>
          <p>Both XQuery and XSLT provide capabilities for XSD-based schema validation in earlier versions of the specifications,
          and those are retained in 4.0. This function provides additional capability:</p>
          <ulist>
             <item><p>It is possible to control validation more precisely, through a wider range of options;</p></item>
             <item><p>It is possible to validate different instance documents against different schemas;</p></item>
             <item><p>Information about any invalidities is made available to the application, rather than simply causing a dynamic error;</p></item>
             <item><p>The capability is provided by means of a function rather than custom syntax, making it easier
             to integrate into an application.</p></item>
             <item><p>The capability is available through XPath alone, and therefore with host languages other than
             XQuery and XSLT.</p></item>
          </ulist>
          <p>Three possible ways of using the function include:</p>
          <ulist>
             <item><p>To simply test whether or not a document is valid against a schema, set the options
             <code>return-typed-node</code> and <code>return-error-details</code> to <code>false</code>,
             and simply test the value of the <code>is-valid</code> field returned when the validation function
             is called.</p></item>
             <item><p>To obtain a typed XDM tree from an input document that is expected to be valid, set the
             option <code>return-typed-node</code> to true. On return from the validation function, test the
             value of the <code>is-valid</code> field; call <function>fn:error</function> if the value is false;
             otherwise use the <code>typed-node</code> property of the result. The main benefit of using a typed
             XDM tree is that it allows static type checking of path expressions: this benefit only applies
             when the schema used for validation is the imported schema used in the static context. However, there
             are cases where validation against a different schema is appropriate, for example when validating the
             result of one query or transformation that is to be used as input to another.</p></item>
             <item><p>To validate an input document and provide feedback to the document author about any validity
             problems that were found, set <code>return-error-details</code> to <code>true</code>. If the result
             of the validation function has <code>is-valid = false()</code>, process the returned <code>error-details</code>.
             The information available for this part of the processing may not be 100% interoperable, though with care it
             should be possible to write the query in such a way that it works with different processors.</p></item>
          </ulist>
          <p>The function has no effect on the static context. Schemas loaded using this function, either directly or
          via the effect of <code>xsi:schemaLocation</code> and <code>xsi:noNamespaceSchemaLocation</code> attributes, are not
          added to the static context and have no effect on any other validation episodes. A processor may cache schema
          components to reduce the cost of processing the same schema repeatedly, but this has no observable effect other than
          on performance.</p>
       </fos:notes>
       <fos:examples>
          <fos:example>
             <fos:test spec="XQuery">
                <fos:expression><eg><![CDATA[
let $schema := 
  <xs:schema>
    <xs:element name="distance" type="xs:decimal"/>
  </xs:schema>
let $validator := xsd-validator({'schema': $schema})
return ($validator(<distance>8.5</distance>)?is-valid,
        $validator(<distance>8.5km</distance>)?is-valid)
                   ]]></eg></fos:expression>
                <fos:result>true(), false()</fos:result>
             </fos:test>
             <fos:test spec="XQuery">
                <fos:expression><eg><![CDATA[
let $schema := 
  <xs:schema>
    <xs:element name="distance" type="xs:decimal"/>
  </xs:schema>
let $validator := xsd-validator({'schema': $schema})
let $typed-result := $validator(<distance>8.5</distance>)?typed-node
return $typed-result instance of element(distance, xs:decimal)
]]></eg></fos:expression>
                <fos:result>true()</fos:result>
             </fos:test>
          </fos:example>
       </fos:examples>
      <fos:changes>
         <fos:change issue="1271" PR="1933" date="2025-04-29"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="serialize" prefix="fn">
      <fos:signatures>
         <fos:proto name="serialize" return-type="xs:string">
            <fos:arg name="input" type="item()*" usage="absorption"/>
            <fos:arg name="options" type="(element(output:serialization-parameters) | map(*))?" usage="absorption" default="{}" example="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>This function serializes the supplied input sequence <code>$input</code> as described in
               <bibref
               ref="xslt-xquery-serialization-31"
            />, returning the serialized representation
            of the sequence as a string.</p>
      </fos:summary>
      <fos:rules>
         <p>The value of the first argument <code>$input</code> acts as the input sequence to the
            serialization process, which starts with sequence normalization.</p>
         <p>The second argument <code>$options</code> provides serialization parameters.
            These may be supplied in either  of two forms:</p>

         <olist>
            <item>
               <p>As an <code>output:serialization-parameters</code>
               element, having the format described in <xspecref
                     spec="SER31" ref="serparams-in-xdm-instance"
                     />. In this case the type of the supplied
               argument must match the required type <code>element(output:serialization-parameters)</code>.</p>
            </item>
            <item>
               <p>As a map. In this case the type of the supplied argument must match the required type <code>map(*)</code></p>
            </item>
         </olist>

         <p>The single-argument version of this function has the same effect as the two-argument
            version called with <code>$options</code> set to the empty sequence. This in turn is the
            same as the effect of passing an <code>output:serialization-parameters</code> element
            with no child elements.</p>

         <p>The final stage of serialization, that is, encoding, is skipped. If the serializer does
            not allow this phase to be skipped, then the sequence of octets returned by the
            serializer is decoded into a string by reversing the character encoding performed in the
            final stage.</p>

         <p>If the second argument is omitted, or is supplied in the form of an <code>output:serialization-parameters</code>
         element, then the values of any serialization parameters that are not explicitly specified is <termref
               def="implementation-defined"
            >implementation-defined</termref>,
         and may depend on the context.</p>

         <p>If the second argument is supplied as a map, then the <termref
               def="option-parameter-conventions"
            >option parameter conventions</termref>
         apply. In this case:</p>

         <olist>
            <item>
               <p>Each entry in the map defines one serialization parameter.</p>
            </item>
            <item>
               <p>The key of the entry is an <code>xs:string</code> value in the cases of parameter names defined in these specifications, or an
            <code>xs:QName</code> (with non-absent namespace) in the case of implementation-defined serialization parameters.</p>
            </item>
            <item>
               <p>The required type of each parameter, and its default value, are defined by the following table. The default
            value is used when the map contains no entry for the parameter in question, and also when an entry is present, with the
            empty sequence as its value. The table also indicates how the value of the map entry is to be interpreted in cases
            where further explanation is needed.</p>
            </item>
         </olist>
         <!--<item><p>The value part of the entry has a required type defined by the following rules, which are organized according to the type
               defined for the parameter in the schema for serialization parameters:</p>
               <olist>
                  <item><p>Where the type is <code>yes-no-type</code>, then an <code>xs:boolean</code> value
                  where <code>true</code> represents <code>"yes"</code> and <code>false</code> represents <code>"no"</code>.</p></item>
                  <item><p>Where the type is <code>yes-no-omit-type</code>, then an optional <code>xs:boolean</code> value
                     where <code>true</code> represents <code>"yes"</code>, <code>false</code> represents <code>"no"</code>, and the empty sequence represents <code>"omit"</code>.</p></item>
                  <item><p>For any other type derived from <code>xs:string</code>, an instance of <code>xs:string</code> that is
                  castable to the required type.</p></item>
                  <item><p>For the union type <code>method-type</code>, an instance of either <code>xs:string</code> or <code>xs:QName</code>
                  as appropriate.</p></item>
                  <item><p>For <code>decimal-param-type</code>, an instance of <code>xs:decimal</code>.</p></item>
                  <item><p>For <code>QNames-type</code>, either a sequence or an array of <code>xs:QName</code> values.</p></item>
                  <item><p>For the <code>use-character-maps</code> parameter, a map, whose keys are the characters to be mapped (as <code>xs:string</code> instances), and whose
                     corresponding values are the strings to be substituted for these characters. The <termref def="option-parameter-conventions">option parameter conventions</termref>
                  apply recursively to this nested map.</p></item>
               </olist>
               <note><p>If the supplied value is of the wrong type for the particular parameter, for example if the value of <code>indent</code>
                  is a string rather than a boolean, then as defined by the <termref def="option-parameter-conventions">option parameter conventions</termref>,
                  a type error <xerrorref spec="XP" class="TY" code="0004"/> is raised. 
                  If the value is of the correct type, but does not satisfy the rules for that
                  parameter defined in <bibref ref="xslt-xquery-serialization-31"/>, then a dynamic error 
                  <xerrorref spec="SER31" class="PM" code="0016"/> is raised.
               </p></note>
            </item>
            <item><p>If no entry is present in the map for a particular serialization parameter name, then that parameter takes a default value as defined in the
            following table:</p>-->
         <table role="no-code-break data">
            <thead>
               <tr>
                  <th>Parameter</th>
                  <th>Required type</th>
                  <th>Interpretation</th>
                  <th>Default Value</th>
               </tr>
            </thead>
            <tbody>
               <tr>
                  <td>
                     <code>allow-duplicate-names</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>no</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>byte-order-mark</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>no</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>canonical</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true()</code> means <code>"yes"</code>, <code>false()</code> means <code>"no"</code></td>
                  <td>
                     <code>no</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>cdata-section-elements</code>
                  </td>
                  <td>
                     <code>xs:QName*</code>
                  </td>
                  <td/>
                  <td>
                     <code>()</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>doctype-public</code>
                  </td>
                  <td>
                     <code>xs:string?</code>
                  </td>
                  <td>Zero-length string and <code>()</code> both represent <code>"absent"</code></td>
                  <td>absent</td>
               </tr>
               <tr>
                  <td>
                     <code>doctype-system</code>
                  </td>
                  <td>
                     <code>xs:string?</code>
                  </td>
                  <td>Zero-length string and <code>()</code> both represent <code>"absent"</code></td>
                  <td>absent</td>
               </tr>
               <tr>
                  <td>
                     <code>encoding</code>
                  </td>
                  <td>
                     <code>xs:string?</code>
                  </td>
                  <td/>
                  <td>
                     <code>UTF-8</code>
                  </td>
               </tr>
               <tr diff="add" at="2023-03-31">
                  <td>
                     <code>escape-solidus</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>yes</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>escape-uri-attributes</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>yes</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>html-version</code>
                  </td>
                  <td>
                     <code>xs:decimal?</code>
                  </td>
                  <td/>
                  <td>
                     <code>5</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>include-content-type</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>yes</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>indent</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>no</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>item-delimiter</code>
                  </td>
                  <td>
                     <code>xs:string?</code>
                  </td>
                  <td/>
                  <td>absent</td>
               </tr>
               <tr>
                  <td>
                     <code>json-lines</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>no</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>json-node-output-method</code>
                  </td>
                  <td>
                     <code>(xs:string | xs:QName)?</code>
                  </td>
                  <td>See Notes 1, 2</td>
                  <td>
                     <code>xml</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>media-type</code>
                  </td>
                  <td>
                     <code>xs:string?</code>
                  </td>
                  <td/>
                  <td>(a media type suitable for the chosen <code>method</code>)</td>
               </tr>
               <tr>
                  <td>
                     <code>method</code>
                  </td>
                  <td>
                     <code>(xs:string | xs:QName)?</code>
                  </td>
                  <td>See Notes 1, 2</td>
                  <td>
                     <code>xml</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>normalization-form</code>
                  </td>
                  <td>
                     <code>xs:string?</code>
                  </td>
                  <td/>
                  <td>
                     <code>none</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>omit-xml-declaration</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>yes</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>standalone</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code>, <code>()</code> means <code>"omit"</code></td>
                  <td>
                     <code>omit</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>suppress-indentation</code>
                  </td>
                  <td>
                     <code>xs:QName*</code>
                  </td>
                  <td/>
                  <td>
                     <code>()</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>undeclare-prefixes</code>
                  </td>
                  <td>
                     <code>xs:boolean?</code>
                  </td>
                  <td><code>true</code> means <code>"yes"</code>, <code>false</code> means <code>"no"</code></td>
                  <td>
                     <code>no</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>use-character-maps</code>
                  </td>
                  <td>
                     <code>map(xs:string, xs:string)?</code>
                  </td>
                  <td>See Note 3</td>
                  <td>
                     <code>{}</code>
                  </td>
               </tr>
               <tr>
                  <td>
                     <code>version</code>
                  </td>
                  <td>
                     <code>xs:string?</code>
                  </td>
                  <td/>
                  <td>
                     <code>1.0</code>
                  </td>
               </tr>
            </tbody>
         </table>

         <p>Notes to the table:</p>

         <olist>
            <item>
               <p>The notation <code>(A | B)</code> represents a union type whose member types are <code>A</code>
            and <code>B</code>.</p>
            </item>
            <item>
               <p>If an <code>xs:QName</code> is supplied <phrase>for the <code>method</code> or <code>json-node-output-method</code> 
               options,</phrase> then it must have a non-absent namespace URI. This
            means that system-defined serialization methods such as <code>xml</code> and <code>json</code>
            are defined as strings, not as <code>xs:QName</code> values.</p>
            </item>
            <item>
               <p><phrase>For the <code>use-character-maps</code> option</phrase>, the value is a map, whose keys 
               are the characters to be mapped (as <code>xs:string</code> instances),
            and whose corresponding values are the strings to be substituted for these characters. 
            </p>
            </item>
         </olist>

      </fos:rules>
      <fos:errors>
         <p>A type error <xerrorref spec="XP" class="TY" code="0004"
               /> occurs if the <code>$options</code> argument
            is present and does not match either of the types <code>element(output:serialization-parameters)?</code>
         or <code>map(*)</code>.</p>
         <note>
            <p>This is defined as a type error so that it can be enforced via the function signature by implementations
         that generalize the type system in a suitable way.</p>
         </note>
         <p>If the host language makes serialization an optional feature and the implementation does
            not support serialization, then a dynamic error <errorref
               class="DC" code="0010"/> is
            raised.</p>
         <p>When the second argument is supplied as a map, 
            and the supplied value is of the wrong type for the particular parameter, for example if the value of <code>indent</code>
         is a string rather than a boolean, then as defined by the <termref
               def="option-parameter-conventions"
               >option parameter conventions</termref>,
         a type error <xerrorref spec="XP"
               class="TY" code="0004"
               /> is raised. 
         If the value is of the correct type, but does not satisfy the rules for that
         parameter defined in <bibref
               ref="xslt-xquery-serialization-31"/>, then a dynamic error 
         <xerrorref
               spec="SER31" class="PM" code="0016"
               /> is raised. (For example, this occurs if the map supplied to
         <code>use-character-maps</code> includes a key that is a string whose length is not one (1)).</p>
         <p>If any serialization error occurs, including the detection of an invalid value for a
            serialization parameter as described above, this results in the <function>fn:serialize</function> call failing with
            a dynamic error.</p>
      </fos:errors>
      <fos:notes>
         <p>One use case for this function arises when there is a need to construct an XML document
            containing nested XML documents within a CDATA section (or on occasions within a
            comment). See <function>fn:parse-xml</function> for further details.</p>
         <p>Another use case arises when there is a need to call an extension function that expects
            a lexical XML document as input.</p>
         <p>Another use case for this function is serializing instances of the data model into a human
            readable format for the purposes of debugging. Using the <xspecref
               spec="SER31" ref="adaptive-output"
            /> by specifying it as the output method defined in the second argument via 
            <code>output:serialization-parameters</code>, allows for serializing any valid
            XDM instance without raising a serialization error.</p>
         <p>There are also use cases where the application wants to post-process the output of a
            query or transformation, for example by adding an internal DTD subset, or by inserting
            proprietary markup delimiters such as the <code>&lt;% ... %&gt;</code> used by some
            templating languages.</p>
         <p>The ability to specify the serialization parameters in an <code>output:serialization-parameters</code>
         element provides backwards compatibility with the 3.0 version of this specification; the ability to
         use a map takes advantage of new features in the 3.1 version. The default parameter values are
         implementation-defined when an <code>output:serialization-parameters</code>
            element is used (or when the argument is omitted), but are fixed by this specification in the
         case where a map (including the empty map) is supplied for the argument.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>Given the variables:</p>
         </fos:example>
         <fos:variable name="params" as="element()" id="v-serialize-params"><![CDATA[<output:serialization-parameters 
    xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
  <output:omit-xml-declaration value="yes"/>
</output:serialization-parameters>]]>
         </fos:variable>
         <fos:variable name="data" as="element()" id="v-serialize-data"><![CDATA[<a b="3"/>]]>
         </fos:variable>
         <fos:example>
            <p>The following call might produce the output shown:</p>
         </fos:example>
         <fos:example>
            <fos:test use="v-serialize-data v-serialize-params" spec="XQuery">
               <fos:expression><![CDATA[serialize($data, $params)]]></fos:expression>
               <fos:result><![CDATA['<a b="3"/>']]></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>The following call would also produce the output shown (though the second argument could equally well be supplied
               as the empty map (<code>{}</code>), since both parameters are given their default values):</p>
         </fos:example>
         <fos:example>
            <fos:test use="v-serialize-data" spec="XQuery">
               <fos:expression><eg><![CDATA[serialize(
  $data,
  { "method": "xml", "omit-xml-declaration": true() }
)]]></eg></fos:expression>
               <fos:result><![CDATA['<a b="3"/>']]></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>serialize({ "a": "AB", "b": "BC" }, { "method": "adaptive" })</fos:expression>
               <fos:result>'{"a":"AB","b":"BC"}'</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test spec="XQuery">
               <fos:expression><eg>
serialize(
  array { "a", 3, attribute test { "true" } },
  { "method": "adaptive" 
})
</eg></fos:expression>
               <fos:result>'["a",3,test="true"]'</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change PR="2259" date="2025-11-03" issue="938">
            <p>A new parameter <code>canonical</code> is available to give control
            over serialization of XML, XHTML, and JSON.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="parse-html" prefix="fn">
      <fos:signatures>
         <fos:proto name="parse-html" return-type="document-node(*:html)?">
            <fos:arg name="value" type="(xs:string | xs:hexBinary | xs:base64Binary)?"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>This function takes as input an HTML document, and returns the
            document node at the root of an XDM tree representing the parsed document.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>In other cases, <code>$value</code> is expected to contain an HTML document supplied
         either as a string or a binary value.</p>
         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>
         
         <fos:options>
            <fos:option key="encoding">
               <fos:meaning>
                  <p>The character encoding to use to decode a sequence of octets that
                  represents an HTML document. Note that encoding names are case-insensitive.</p>
               </fos:meaning>
               <fos:type>xs:string</fos:type>
            </fos:option>
            <fos:option key="fail-on-error">
               <fos:meaning>
                  <p>Indicates whether the function should fail with a dynamic error if the input
                     is not syntactically valid.</p>
               </fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">
                     Parsing errors should be handled as described in 
                     <bibref ref="html5"/> section 13.2.2, <emph>Parse Errors</emph>.
                  </fos:value>
                  <fos:value value="true">
                     A parsing error should result in the function failing with a dynamic error.
                  </fos:value>
               </fos:values>
            </fos:option>
            <!--<fos:option key="include-template-content">
               <fos:meaning>
                  <p>Defines how to handle elements in the <code>HTMLTemplateElement.content</code>
                     property.</p>
                  <p>If this option is <code>true</code>, the <code>template</code> element’s
                     children are the children of the <code>content</code> property’s document
                     fragment node.</p>
                  <p>If this option is <code>false</code>, the <code>template</code> element’s
                     children are the empty sequence.</p>
                  <p>The default behaviour is
                     <termref def="implementation-defined">implementation-defined</termref>.</p>
                  <note>
                     <p>This allows an implementation to support the behaviour defined in
                        <bibref ref="html5"/> section 4.12.3.1, <emph>Interaction of
                        <code>template</code> elements with XSLT and XPath</emph>:</p>
                     <olist>
                        <item>
                           <p>This option would default to <code>true</code> for an XSLT processor
                              operating on an HTML DOM constructed from an XHTML document.</p>
                        </item>
                        <item>
                           <p>This option would default to <code>false</code> for an XPath processor
                              using the <bibref ref="dom-ls"/> section 8, <emph>XPath</emph> APIs.</p>
                        </item>
                     </olist>
                  </note>
               </fos:meaning>
               <fos:type>xs:boolean</fos:type>
            </fos:option>-->
         </fos:options>
         
         <p>The <termref def="option-parameter-conventions"/> apply.</p>
         
         <p>If <code>$value</code> is not the empty sequence, an input byte stream is constructed as follows:</p>
         <olist>
            <item>
               <p>If <code>$value</code> is an <code>xs:string</code>, then in principle no decoding is needed.
                  Conceptually, however, the HTML parsing algorithm always starts by decoding an octet
                  stream. The string is therefore first encoded using UTF-8, and the resulting octet
                  stream is then passed to the HTML parser with a <term>known definite encoding</term>
                  of UTF-8, as described in <bibref ref="html5"/> section 13.2.3.1,
                  <emph>Parsing with a known character encoding</emph>.</p>
               <p>If the first codepoint of the string is <char>U+FEFF</char>, this should be stripped, since
               it might otherwise lead to an incorrect encoding inference.</p>
            </item><item>
               <p>If the type of <code>$value</code> is a sequence of octets (<code>xs:hexBinary</code> or
                  <code>xs:base64Binary</code>) the encoding of the input byte stream is determined in a
                  way consistent with <bibref ref="html5"/> section 13.2.3.2, <emph>Determining the character
                  encoding</emph>:</p>
               <olist>
                  <item>
                     <p>The <code>encoding</code> key of <code>$options</code> is interpreted in step 2 of
                        <emph>Determining the character encoding</emph> as the user instructing the user
                        agent to override the document’s character encoding with the specified encoding.</p>
                  </item><item>
                     <p>If the <code>encoding</code> key of <code>$options</code> is not specified, step 2
                        of <emph>Determining the character encoding</emph> is skipped.</p>
                  </item>
               </olist>
            </item>
         </olist>
         
         
         <olist>
            <item>
               <p>Tokenizing the byte stream according to the HTML parsing algorithm as described in
                  <bibref ref="html5"/> section 13.2.5, <emph>Tokenization</emph>.</p>
            </item><item>
               <p>Constructing a <code>HTMLDocument</code> object for HTML documents, or an
                  <code>XMLDocument</code> for XML/XHTML documents as described in 
                  <bibref ref="html5"/> section 13.2.6, <emph>Tree construction</emph>.</p>
            </item><item>
               <p>Building an XDM representation of the <code>HTMLDocument</code> or <code>XMLDocument</code>
                  according to the rules in <specref ref="html-xdm-mapping"/>.</p>
            </item>
         </olist>
         
         <p>The implementation <rfc2119>should</rfc2119> process any input HTML that adheres to the current
         practice of mainstream web browsers, as this evolves over time. Since this is defined
         by a “living standard” (see <bibref ref="html5"/>), no specific version is prescribed. 
         An implementation <rfc2119>may</rfc2119>
         define additional options to control aspects of the HTML parsing algorithm, including the selection
         of a specific HTML parsing library; it may also provide options to process alternative HTML versions
         or dialects.</p>
         
         <p>The implementation <rfc2119>should</rfc2119> recognize and process XHTML (referred to
            in <bibref ref="html5"/> as the XML concrete syntax of HTML).</p>
         
         <p>The function is <termref def="dt-nondeterministic">nondeterministic with respect to node identity</termref>:
            that is, if the function is called twice with the same arguments, it is
            <termref def="implementation-dependent"/> whether the same node is returned on both
            occasions.</p>
         
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="DC" code="0011"/> if the content of
            <code>$value</code> is not a well-formed HTML document. This includes the case
            where <code>$value</code> cannot be decoded using the specified encoding.</p>

      </fos:errors>
      <fos:notes>
         <p>If the HTML parser accepts a string as the input then that may be used directly when
            <code>$value</code> is an <code>xs:string</code> instead of converting the string to
            a sequence of octets in an <termref def="implementation-dependent"/> encoding. The HTML
            parser must not perform character encoding processing on that input, treating the HTML
            string as being in a known character encoding that matches the encoding of the string.</p>
         
         <p>The WHATWG Encoding specification defines the ISO 8859-1 (latin1) and ASCII encodings as
            aliases of the windows-1252 encoding.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>The expression <code>parse-html(())</code> returns <code>()</code>.</p>
            <p>The expression <code>parse-html("&lt;p>Hello&lt;/p>")</code> returns an XDM

               document node equivalent to the result of parsing the XML 
               <code><![CDATA[<html xmlns='http://www.w3.org/1999/xhtml'><head/><body><p>Hello</p></body></html>]]></code></p>
            <p>The expression <code>parse-html("&lt;p>Hi&lt;/p>", method:=&quot;html&quot;)</code>
               is equivalent to <code>parse-html("&lt;p>Hi&lt;/p>")</code>.</p>

         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="74 850 1799 1889 1891 2210" PR="259 956" date="2023-01-10"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="html-doc" prefix="fn">
      <fos:signatures>
         <fos:proto name="html-doc" return-type="document-node(*:html)?">
            <fos:arg name="source" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Reads an external resource containing HTML, and returns the result of parsing the resource as HTML.</p>
      </fos:summary>
      <fos:rules>
         <p>The effect of the two-argument function call <code>fn:html-doc($H, $M)</code>is equivalent to the function composition
            <code>fn:unparsed-binary($H) => fn:parse-html($M)</code>.</p>
         <p>If <code>$source</code> is the empty sequence, the function returns the empty sequence.</p>
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
      </fos:rules>
      <fos:errors>
         <p>The function may raise any error defined for the <function>fn:unparsed-binary</function>
         or <function>fn:parse-html</function> functions.</p>
      </fos:errors>
      <fos:changes>
         <fos:change issue="748" PR="2013" date="2025-05-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="position" prefix="fn">
      <fos:signatures>
         <fos:proto name="position" return-type="xs:integer"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the context position from the dynamic context.</p>
      </fos:summary>
      <fos:rules>
         <p>Returns the context position from the dynamic context. (See <xspecref spec="XP40"
               ref="id-xp-evaluation-context-components"/>.)</p>
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <xerrorref spec="XP" class="DY" code="0002" type="type"
               /> if
            the context value is <xtermref ref="dt-absent" spec="DM40"
               >absent</xtermref>.</p>
      </fos:errors>
   </fos:function>
   <fos:function name="last" prefix="fn">
      <fos:signatures>
         <fos:proto name="last" return-type="xs:integer"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the context size from the dynamic context.</p>
      </fos:summary>
      <fos:rules>
         <p>Returns the context size from the dynamic context. (See <xspecref spec="XP40"
               ref="id-xp-evaluation-context-components"/>.)</p>
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <xerrorref spec="XP" class="DY" code="0002" type="type"
               /> if
            the context <phrase>size</phrase> is <xtermref ref="dt-absent"
               spec="DM40">absent</xtermref>.</p>
      </fos:errors>
      <fos:notes>
         <p>Under most circumstances, the context size is absent only if the context value is absent. However, XSLT 3.0 with
         streaming defines situations in which the context value and context position are known, but the context size is unknown.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>(1 to 20)[last() - 1]</fos:expression>
               <fos:result>19</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="current-dateTime" prefix="fn">
      <fos:signatures>
         <fos:proto name="current-dateTime" return-type="xs:dateTimeStamp"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the current date and time (with timezone).</p>
      </fos:summary>
      <fos:rules>
         <p>Returns the current dateTime (with timezone) from the dynamic context. (See <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"
               />.) This is an
               <code>xs:dateTime</code> that is current at some time during the evaluation of a
            query or transformation in which <function>fn:current-dateTime</function> is executed.</p>
         <p>This function is <termref def="dt-deterministic"
               />. The precise instant during the query
            or transformation represented by the value of <code>fn:current-dateTime()</code> is
            <termref
               def="implementation-dependent">implementation-dependent</termref>.</p>
         <p>If the implementation supports data types from XSD 1.1 then the returned value will be
            an instance of <code>xs:dateTimeStamp</code>. Otherwise, the only guarantees are that it
            will be an instance of <code>xs:dateTime</code> and will have a timezone component.</p>
      </fos:rules>
      <fos:notes>
         <p>The returned <code>xs:dateTime</code> will always have an associated timezone, which
            will always be the same as the implicit timezone in the dynamic context</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>current-dateTime()</fos:expression>
               <fos:result narrative="true">An <code>xs:dateTimeStamp</code>
               corresponding to the current date and time. For example, a call of
                  <code>current-dateTime()</code> might return
                  <code>2024-05-12T18:17:15.125Z</code> corresponding to the current time on May 12,
               2024 in timezone <code>Z</code>. </fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="current-date" prefix="fn">
      <fos:signatures>
         <fos:proto name="current-date" return-type="xs:date"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the current date.</p>
      </fos:summary>
      <fos:rules>
         <p>Returns <code>xs:date(fn:current-dateTime())</code>. This is an <code>xs:date</code>
            (with timezone) that is current at some time during the evaluation of a query or
            transformation in which <function>fn:current-date</function> is executed.</p>
         <p>This function is <termref def="dt-deterministic"
               />. The precise instant during the query
            or transformation represented by the value of <function>fn:current-date</function> is <termref
               def="implementation-dependent">implementation-dependent</termref>.</p>
      </fos:rules>
      <fos:notes>
         <p>The returned date will always have an associated timezone, which will always be the same
            as the implicit timezone in the dynamic context</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>current-date()</fos:expression>
               <fos:result narrative="true">An <code>xs:date</code> corresponding to the
               current date. For example, a call of <code>current-date()</code> might return
                  <code>2004-05-12+01:00</code>.</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="current-time" prefix="fn">
      <fos:signatures>
         <fos:proto name="current-time" return-type="xs:time"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the current time.</p>
      </fos:summary>
      <fos:rules>
         <p>Returns <code>xs:time(fn:current-dateTime())</code>. This is an <code>xs:time</code>
            (with timezone) that is current at some time during the evaluation of a query or
            transformation in which <function>fn:current-time</function> is executed.</p>
         <p>This function is <termref def="dt-deterministic"
               />. The precise instant during the query
            or transformation represented by the value of <code>fn:current-time()</code> is <termref
               def="implementation-dependent">implementation-dependent</termref>.</p>
      </fos:rules>
      <fos:notes>
         <p>The returned time will always have an associated timezone, which will always be the same
            as the implicit timezone in the dynamic context</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>current-time()</fos:expression>
               <fos:result narrative="true">An <code>xs:time</code> corresponding to the
               current time. For example, a call of <code>current-time()</code> might return
                  <code>23:17:00.000-05:00</code>.</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="implicit-timezone" prefix="fn">
      <fos:signatures>
         <fos:proto name="implicit-timezone" return-type="xs:dayTimeDuration"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value of the implicit timezone property from the dynamic context. </p>
      </fos:summary>
      <fos:rules>
         <p>Returns the value of the implicit timezone property from the dynamic context. Components
            of the dynamic context are described in <xspecref
               spec="XP40" ref="id-xp-evaluation-context-components"/>.</p>
      </fos:rules>
   </fos:function>
   <fos:function name="default-collation" prefix="fn">
      <fos:signatures>
         <fos:proto name="default-collation" return-type="xs:string"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value of the default collation property from the <phrase diff="chg" at="2023-05-19">dynamic</phrase> context. </p>
      </fos:summary>
      <fos:rules>
         <p>Returns the value of the default collation property from the 
            <phrase diff="chg" at="2023-05-19">dynamic</phrase> context context. Components
            of the dynamic context are described in <xspecref
               spec="XP40" ref="eval_context"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>The default collation property can never be absent. If it is not explicitly defined, a
            system defined default can be invoked. If this is not provided, the Unicode codepoint
            collation (<code>http://www.w3.org/2005/xpath-functions/collation/codepoint</code>) is
            used. </p>
         <p diff="add" at="2023-05-19">In most cases, the default collation is known statically,
         and a call on this function can therefore be pre-evaluated during static analysis. The only
         notable exception is when a call on <code>default-collation()</code> is used to define
         the default value of a parameter to a user-defined function. In this case it is interpreted
         as a reference to the default collation in the context of the relevant function call,
         which may differ from the default collation of the function definition.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="default-language" prefix="fn">
      <fos:signatures>
         <fos:proto name="default-language" return-type="xs:language"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="default-language">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value of the default language property from the dynamic context. </p>
      </fos:summary>
      <fos:rules>
         <p>Returns the value of the default language property from the dynamic context. Components
            of the dynamic context are described in <xspecref
               spec="XP40" ref="eval_context"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>The default language property can never be absent. The functions <function>fn:format-integer</function>,
         <function>fn:format-date</function>, <function>fn:format-time</function>, and <function>fn:format-dateTime</function>
         are defined to use the default language if no explicit language is supplied. The default language
         may play a role in selection of a default collation, but this is not a requirement.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="static-base-uri" prefix="fn">
      <fos:signatures>
         <fos:proto name="static-base-uri" return-type="xs:anyURI?"/>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p diff="chg" at="2023-05-19">This function returns the value of the <term>executable base URI</term> property from the dynamic
            context.</p>
      </fos:summary>
      <fos:rules>
         <p diff="chg" at="2023-05-19">The function (despite its name) 
            returns the value of the <term>executable base URI</term> property from the dynamic context.
            If the property is absent, the empty sequence is returned.</p>
         <p diff="chg" at="2023-05-19">Components of the dynamic context are described in <xspecref spec="XP40"
               ref="eval_context"/> .</p>
      </fos:rules>
      <fos:notes>
         <p>The executable base URI will in many cases be the same as the static base URI in the static context.
            However, XQuery and XSLT give an implementation freedom to use different base URIs during
            the static analysis phase and the dynamic evaluation phase, that is, for retrieval of compile-time
            and run-time resources respectively. This is appropriate when the implementation allows
            the output of static analysis (a “compiled” query or stylesheet) to be deployed for execution
            to a different location from the one where static analysis took place. In this situation, the
               <function>fn:static-base-uri</function> function should return a URI suitable for locating
            resources needed during dynamic evaluation.</p>
         <p>If a call on the <function>fn:static-base-uri</function> function appears within the expression used
         to define the value of an optional parameter to a user-defined function, then the value supplied
         to the function (if the argument is omitted) will be the executable base URI from the dynamic
         context of the function caller. This allows such a function to resolve relative URIs supplied
         in other parameters to the same function.</p>
      </fos:notes>
   </fos:function>
   <fos:function name="function-lookup" prefix="fn">
      <fos:signatures>
         <fos:proto name="function-lookup" return-type="fn(*)?">
            <fos:arg name="name" type="xs:QName"/>
            <fos:arg name="arity" type="xs:integer"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
         
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <phrase diff="chg" at="2023-05-26">a function item</phrase> having a given name and arity, if there is one.</p>
      </fos:summary>
      <fos:rules>
         <p diff="chg" at="2023-05-26">A call to <function>fn:function-lookup</function> starts by looking for a 
            <xtermref spec="XP40" ref="dt-function-definition">function definition</xtermref>
             in the named functions component of the dynamic context
            (specifically, the dynamic context of the call to <function>fn:function-lookup</function>),
            using the expanded QName supplied as <code>$name</code> and the arity supplied as
            <code>$arity</code>. There can be at most one such function definition.</p>
         
         <p>If no function definition can be identified (by name and arity), then the empty sequence
            is returned.</p>
         
         <p diff="chg" at="2023-05-26">If a function definition is identified, then a function item is obtained from the function
         definition using the same rules as for evaluation of a named function reference 
         (see <xspecref spec="XP40" ref="id-named-function-ref"/>). The captured context of
         the returned function item (if it is context dependent) is the static and dynamic context of 
         the call on <function>fn:function-lookup</function>.</p>

 
         <p>If the arguments to <function>fn:function-lookup</function> identify a function that is present
            in the static context of the function call, the function will always return the same
            function that a static reference to this function would bind to. If there is no such
            function in the static context, then the results depend on what is present in the
            dynamic context, which is <termref
               def="implementation-defined">implementation-defined</termref>.</p>



      </fos:rules>
      <fos:errors>
         <p diff="add" at="2023-12-12">An error is raised if the identified function depends on
            components of the static or dynamic context that are not present, or that have
            unsuitable values. For example <xerrorref spec="XP"
               class="DY" code="0002" type="type"/> is raised for the call
            <code>function-lookup( #fn:name, 0 )</code>
            if the context value is absent, and <errorref class="DC" code="0001" type="dynamic"
            /> is raised for the call <code>function-lookup( #fn:id, 1 )</code> if the
            context value is not a single node in a tree that is rooted at a document node.
            The error that is raised is the same as the error that would be raised by the
            corresponding function if called with the same static and dynamic context.</p>
      </fos:errors>

      <fos:notes>
         <p>This function can be useful where there is a need to make a dynamic decision on which of
            several statically known functions to call. It can thus be used as a substitute for
            polymorphism, in the case where the application has been designed so several functions
            implement the same interface.</p>
         <p>The function can also be useful in cases where a query or stylesheet module is written
            to work with alternative versions of a library module. In such cases the author of the
            main module might wish to test whether an imported library module contains or does not
            contain a particular function, and to call a function in that module only if it is
            available in the version that was imported. A static call would cause a static error if
            the function is not available, whereas getting the function using
               <function>fn:function-lookup</function> allows the caller to take fallback action in this
            situation. </p>
         <p>If the function that is retrieved by <function>fn:function-lookup</function> is <termref
               def="dt-context-dependent"
               >context-dependent</termref>, that is, if it has
            dependencies on the static or dynamic context of its caller, the context that applies is
            the static and/or dynamic context of the call to the <function>fn:function-lookup</function>
            function itself. The context thus effectively forms part of the closure of the returned
            function. This mainly applies when the target of
               <function>fn:function-lookup</function> is a built-in function, because user-defined
            functions typically have no dependency on the static or dynamic context of the function call
            (an exception arises when the expressions used to define default values for parameters
            are context-dependent). The rule
            applies recursively, since <function>fn:function-lookup</function> is itself a context-dependent
            built-in function. </p>
         <p>However, the static and dynamic context of the call to <function>fn:function-lookup</function>
            may play a role even when the selected function definition is not itself context dependent,
            if the expressions used to establish default parameter values are context dependent.</p>
         <p>User-defined XSLT or XQuery functions should be accessible to <function>fn:function-lookup</function>
         only if they are statically visible at the location where the call to <function>fn:function-lookup</function>
         appears. This means that private functions, if they are not statically visible in the containing
         module, should not be accessible using <function>fn:function-lookup</function>.</p>
         <p diff="add" at="2023-05-26">The function identity is determined in the same way as for
         a named function reference. Specifically, if there is no context dependency, two calls
         on <function>fn:function-lookup</function> with the same name and arity must return the same function.</p>
         <p>These specifications do not define any circumstances in which the dynamic context will
            contain functions that are not present in the static context, but neither do they rule
            this out. For example an API <rfc2119>may</rfc2119> provide the ability to add functions
            to the dynamic context, and such functions may potentially be context-dependent. </p>
         
         <p>The mere fact that a function exists and has a name does not of itself mean that the
         function is present in the dynamic context. For example, functions obtained through
         use of the <function>fn:load-xquery-module</function> function are not added to the dynamic context.</p>
         
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>function-lookup( #fn:substring, 2 )( 'abcd', 2 )</fos:expression>
               <fos:result>'bcd'</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>(fn:function-lookup( #xs:dateTimeStamp, 1 ),
                  xs:dateTime#1)[1] ('2011-11-11T11:11:11Z')</eg></fos:expression>
               <fos:result narrative="true">An
                  <code>xs:dateTime</code> value set to the specified date, time, and timezone; if
               the implementation supports XSD 1.1 then the result will be an instance of the
               derived type <code>xs:dateTimeStamp</code>. The query is written to ensure that no
               failure occurs when the implementation does not recognize the type
                  <code>xs:dateTimeStamp</code>.</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>declare namespace zip = "http://expath.org/ns/zip";
let $f := function-lookup( #zip:binary-entry, 2 )
return if (exists($f)) then $f("file:///temp.zip", "index.xml") else ()</eg></fos:expression>
               <fos:result narrative="true">The result of
               calling <code>zip:binary-entry("file:///temp.zip", "index.xml")</code> if the function is available, or
               the empty sequence otherwise.</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="function-name" prefix="fn">
      <fos:signatures>
         <fos:proto name="function-name" return-type="xs:QName?">
            <fos:arg name="function" type="fn(*)"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns the name of the function identified by a function item.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$function</code> refers to a named function, <code>fn:function-name($func)</code>
            returns the name of that function.</p>
         <p>Otherwise (<code>$function</code> refers to an anonymous function),
               <code>fn:function-name($function)</code> returns the empty sequence.</p>
         <p>The prefix part of the returned QName is <termref def="implementation-dependent"
               >implementation-dependent</termref>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>function-name(substring#2)</fos:expression>
               <fos:result><eg>#Q{http://www.w3.org/2005/xpath-functions}substring</eg></fos:result>
               <fos:postamble>The namespace prefix of the returned QName is not predictable.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>function-name(fn($node) { count($node/*) })</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>

      </fos:examples>
   </fos:function>
   <fos:function name="function-arity" prefix="fn">
      <fos:signatures>
         <fos:proto name="function-arity" return-type="xs:integer">
            <fos:arg name="function" type="fn(*)"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns the arity of the function identified by a function item.</p>
      </fos:summary>
      <fos:rules>
         <p>The <function>fn:function-arity</function> function returns the arity (number of arguments) of
            the function identified by <code>$function</code>.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>function-arity(substring#2)</fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>function-arity(fn($node) { name($node) })</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $initial := substring(?, 1, 1)
return function-arity($initial)</eg></fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="function-identity" prefix="fn">
      <fos:signatures>
	     <fos:proto name="function-identity" return-type="xs:string">
            <fos:arg name="function" type="fn(*)"/>		    
	     </fos:proto>
	  </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>         
      </fos:properties>	 
      <fos:summary>
         <p>Returns a string representing the identity of a function item.</p>
      </fos:summary>
	  <fos:rules>
         <p>The <function>fn:function-identity</function> function returns a string that represents
            the identity of <code>$function</code>.</p>
	      <p>The returned string has the property that <code>fn:function-identity($f1)</code>
	      and <code>fn:function-identity($f2)</code> are codepoint-equal if and only if <code>$f1</code>
	      and <code>$f2</code> have the same function identity. Apart from this property, the
	      result is <termref def="implementation-dependent"/>.</p>
	     
	     <p>In the case of maps and arrays, the result follows the following rule:
	        If <code>$X</code> and <code>$Y</code> are both maps or arrays then <code>fn:function-identity($X)</code>
	        <rfc2119>must not</rfc2119> be codepoint-equal to <code>fn:function-identity($Y)</code> unless
	        <code>$X</code> and <code>$Y</code> are indistinguishable, that is unless every operator or function applied
	        to <code>$X</code> returns the same result as for <code>$Y</code>. Even in this case, however, the
	        result of the comparison <code>fn:function-identity($X) eq fn:function-identity($Y)</code>
	        is <termref def="implementation-dependent"/>.</p>
      </fos:rules>
	  <fos:notes>
	     <p>This function enables applications to test whether two expressions or variables
	        reference the same function item. This may be useful, for example, to allow caching
	        of function results to avoid repeated evaluation. The results of previous function
	        invocations might be held in a map whose key is the function identity.</p>
		<p>The function identity, by definition, is generated upon the creation of a function item.
		   Specific expressions that create function items have their own rules for the identity
		   of the returned functions: for example, it is guaranteed that evaluation of a function
		   reference to a system function with no captured context (such as <code>fn:abs#1</code>)
		   will always return the same function item.</p>
		   <p>It is not meaningful to store or compare the result of calling <function>fn:function-identity</function> 
		   across different <termref def="execution-scope">execution scopes</termref>, because the string used 
		   to represent the function identity will generally vary from one execution scope to another.</p>
	     <p>The result of an expression such as <code>function-identity(abs#1) eq function-identity(abs(?))</code>
	     may be either <code>true</code> or <code>false</code>, because it is <termref def="implementation-dependent"/> 
	        whether <code>abs#1</code> and <code>abs(?)</code> return the same function item.</p>
	     <p>Similarly, <code>function-identity({ 1:() }) eq function-identity(map:entry(1, ()))</code>
	     may be either <code>true</code> or <code>false</code>.</p>
	     
	  </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>function-identity(abs#1) eq function-identity(abs#1)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>function-identity(abs#1) eq function-identity(round#1)</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>function-identity({ 1: 0 }) eq function-identity({ 1: 1 })</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>function-identity([ 0 ]) eq function-identity([ 1 ])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1798" PR="1801" date="2025-03-05"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="function-annotations" prefix="fn">
      <fos:signatures>
         <fos:proto name="function-annotations" return-type="map(xs:QName, xs:anyAtomicType*)*">
            <fos:arg name="function" type="fn(*)"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the annotations of the function item.</p>
      </fos:summary>
      <fos:rules>
         <p>The <code>fn:function-annotations</code> function returns the annotations of
            <code>$function</code> as a sequence of 
            <termref def="dt-single-entry-map">single-entry maps</termref>, each associating
            the name of a function annotation with the value of the annotation.
            Note that several annotations on a function can share the same name. The order
            of the annotations is retained.</p>
         <p>The result is a sequence of <termref def="dt-single-entry-map">single-entry maps</termref>, 
            each being an instance of
            <code>map(xs:QName, xs:anyAtomicType*)</code>. 
            If a function (for example, a built-in function) has no annotations,
            the result of the function is the empty sequence.</p>
         <p>For each annotation, a map is returned, with a single entry. The
            key of the map entry is the name of the annotation as an <code>xs:QName</code>.
            The value of the entry is the value of the annotation as a sequence of atomic items.
            If the annotation has no values, the associated value is the empty sequence.</p>
      </fos:rules>
      <fos:notes>
         <p>In the common case where the annotation names are all unique, 
            the result of the function can readily be converted into single map by applying the function 
            <code>map:merge</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>function-annotations(true#0)</eg></fos:expression>
               <fos:result><eg>()</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test spec="XQuery">
               <fos:expression><eg>
declare %private function local:inc($c) { $c + 1 };
function-annotations(local:inc#1)</eg></fos:expression>
               <fos:result><eg>{ #Q{http://www.w3.org/2012/xquery}private : () }</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test spec="XQuery">
               <fos:expression><eg>
let $old := %local:deprecated('0.1', '0.2') fn() {}
let $ann := function-annotations($old)
return map:merge($ann)
</eg></fos:expression>
               <fos:result><eg>{
  #Q{http://www.w3.org/2005/xquery-local-functions}deprecated :
  ("0.1", "0.2") 
}
</eg></fos:result>
            </fos:test>
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="36" PR="710" date="2023-09-17">
            <p>New in 4.0</p>
         </fos:change>
         <fos:change issue="1391" PR="1393" date="2024-08-19">
            <p>Changes the function to return a sequence of key-value pairs rather than a map.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="for-each" prefix="fn">
      <fos:signatures>
         <fos:proto name="for-each" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="action" type="fn(item(), xs:integer) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Applies the function item <code>$action</code> to every item from the sequence <var>$input</var>
            in turn, returning the concatenation of the resulting sequences in order.</p>
      </fos:summary>
      <fos:rules>
         <p>The function calls <code>$action($item, $pos)</code> for each item in <code>$input</code>,
            where <code>$item</code> is the item in question and <code>$pos</code> is its 1-based
            ordinal position in <code>$input</code>. The final result is the sequence concatenation
            of the result of these calls, preserving order.
         </p>
      </fos:rules>
      <fos:equivalent style="dm-primitive">
dm:iterate-sequence($input, $action)  
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>for-each(1 to 5, fn($a) { $a * $a })</fos:expression>
               <fos:result>1, 4, 9, 16, 25</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>for-each(
  ("john", "jane"),
  string-to-codepoints#1
)</eg></fos:expression>
               <fos:result>106, 111, 104, 110, 106, 97, 110, 101</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>for-each(("23", "29"), xs:int#1)</fos:expression>
               <fos:result>23, 29</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>for-each(
  ('one', 'two', 'three'),
  fn($item, $pos) { $pos || '. ' || $item }
)</eg></fos:expression>
               <fos:result>"1. one", "2. two", "3. three"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="516" PR="828" date="2023-11-14">
            <p>The <code>$action</code> callback function accepts an optional position argument.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="filter" prefix="fn">
      <fos:signatures>
         <fos:proto name="filter" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="predicate" type="fn(item(), xs:integer) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns those items from the sequence <code>$input</code> for which the supplied function
               <code>$predicate</code> returns <code>true</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence containing those items from <code>$input</code>
            for which <code>$predicate($item, $pos)</code> returns <code>true</code>, where <code>$item</code>
            is the item in question, and <code>$pos</code> is its 1-based ordinal position within <code>$input</code>.</p>

      </fos:rules>
      <fos:equivalent style="xpath-expression">
for-each(
  $input,
  fn($item, $pos) { if ($predicate($item, $pos)) { $item } }
)
      </fos:equivalent>
      <fos:errors>
         <p>As a consequence of the function signature and the function calling rules, a type error
            occurs if the supplied <code>$predicate</code> function returns anything other than a single
               <code>xs:boolean</code> item or the empty sequence; there is no conversion to an effective boolean
            value, but the empty sequence is interpreted as false.</p>
      </fos:errors>
      <fos:notes>
         <p>If <code>$predicate</code> is an arity-1 function,
            the function call <code>fn:filter($input, $predicate)</code> has a very similar effect to the
            expression <code>$input[$predicate(.)]</code>. There are some differences, however. In the case of
               <function>fn:filter</function>, the function <code>$F</code> is required to return an optional boolean;
            there is no special treatment for numeric predicate values, and no conversion to an
            effective boolean value. Also, with a filter expression <code>$input[$predicate(.)]</code>,
            the focus within the predicate is different from that outside; this means that the use of a
            context-sensitive function such as <code>fn:lang#1</code> will give different results in
            the two cases.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>filter(1 to 10, fn($a) { $a mod 2 = 0 })</fos:expression>
               <fos:result>2, 4, 6, 8, 10</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[filter(parse-xml('<doc><a id="2"/><a/></doc>')//a, fn { @id eq "2" })]]></eg></fos:expression>
               <fos:result><![CDATA[<a id="2"/>]]></fos:result>
               <fos:postamble>The function returns <code>()</code> when there is no <code>@id</code> attribute;
               this is treated as false.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>filter((), lang("en", ?))</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $sequence := (1, 1, 2, 3, 4, 4, 5)
return filter(
  $sequence,
  fn($item, $pos) { $item = $sequence[$pos - 1] }
)</eg></fos:expression>
               <fos:result>1, 4</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="516" PR="828" date="2023-11-14">
            <p>The <code>$predicate</code> callback function accepts an optional position argument.</p>
         </fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="fold-left" prefix="fn">
      <fos:signatures>
         <fos:proto name="fold-left" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="init" type="item()*"/>
            <fos:arg name="action" type="fn(item()*, item()) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Processes the supplied sequence from left to right, applying the supplied function
            repeatedly to each item in turn, together with an accumulated result value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is empty, the function returns <code>$init</code>.</p>
         <p>If <code>$input</code> contains at least one item, the function calls 
            <code>$action($init, $input[1])</code>, returning a value <var>A1</var>.</p>
         <p>If <code>$input</code> contains a second item, the function then calls 
            <code>$action(<var>A1</var>, $input[2])</code>, returning <var>A2</var>; to process the <var>n</var>th
         item it calls <code>$action(<var>A/n-1</var>, $input[<var>N</var>])</code>.</p>
         <p>This continues in the same way until the end of the <code>$input</code> sequence; the final result is
         the result of the last call on <code>$action</code>.</p>

      </fos:rules>
      <fos:equivalent style="xquery-function">
declare function fold-left(
  $input  as item()*,
  $init   as item()*,
  $action as function(item()*, item()) as item()*
) as item()* {
  if (empty($input)) 
  then $init
  else fold-left(tail($input), $action($init, head($input)), $action)
};
      </fos:equivalent>
      <fos:errors>
         <p>As a consequence of the function signature and the function calling rules, a type error
            occurs if the supplied function <code>$action</code> cannot be applied to two arguments, where
            the first argument is either the value of <code>$init</code> or the result of a previous
            application of <code>$action</code>, and the second 
            is any single item from the sequence <code>$input</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>This operation is often referred to in the functional programming literature as
            “folding” or “reducing” a sequence. It typically takes a function that operates on a pair of
            values, and applies it repeatedly, with an accumulated result as the first argument, and
            the next item in the sequence as the second argument. The accumulated result is
            initially set to the value of the <code>$init</code> argument, which is conventionally a
            value (such as zero in the case of addition, one in the case of multiplication, or a
            zero-length string in the case of string concatenation) that causes the function to
            return the value of the other argument unchanged.</p>
         <p>Unlike other functions that apply a user-supplied callback function to successive
         items in a sequence, this function does not supply the current position to the callback function
         as an optional argument. If positional information is required, this can be achieved by
         first forming the sequence <code>$input ! { 'position': position(), 'item': . }</code>
         and then applying the <function>fn:fold-left</function> function to this sequence.</p>
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  1 to 5,
  0,
  fn($a, $b) { $a + $b }
)</eg></fos:expression>
               <fos:result>15</fos:result>
               <fos:postamble>This returns the sum of the items in the sequence</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  (2, 3, 5, 7),
  1,
  fn($a, $b) { $a * $b }
)</eg></fos:expression>
               <fos:result>210</fos:result>
               <fos:postamble>This returns the product of the items in the sequence</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  (true(), false(), false()),
  false(),
  fn($a, $b) { $a or $b }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>This returns <code>true</code> if any item in the sequence has an effective boolean
                  value of <code>true</code></fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  (true(), false(), false()),
  false(),
  fn($a, $b) { $a and $b }
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>This returns <code>true</code> only if every item in the sequence has an effective
                  boolean value of <code>true</code></fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  1 to 5,
  (),
  fn($a, $b) { $b, $a }
)</eg></fos:expression>
               <fos:result>5, 4, 3, 2, 1</fos:result>
               <fos:postamble>This reverses the order of the items in a sequence</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  1 to 5,
  "",
  concat(?, ".", ?)
)</eg></fos:expression>
               <fos:result>".1.2.3.4.5"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  1 to 5,
  "$z",
  concat("$f(", ?, ", ", ?, ")")
)</eg></fos:expression>
               <fos:result>"$f($f($f($f($f($z, 1), 2), 3), 4), 5)"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-left(
  1 to 5,
  {},
  fn($map, $n) { map:put($map, $n, $n * 2) }
)</eg></fos:expression>
               <fos:result>{ 1: 2, 2: 4, 3: 6, 4: 8, 5: 10 }</fos:result>
            </fos:test>
         </fos:example>
         <!--<fos:example>
            <fos:test>
               <fos:expression><eg>
let $input := (11 to 21, 21 to 31)
let $target := 21
return fold-left($input, (),
  fn($result, $curr, $pos) {
    $result, if ($curr = $target) { $pos }
  }
)
</eg></fos:expression>
               <fos:result>11, 12</fos:result>
            </fos:test>
         </fos:example>-->
      </fos:examples>
   </fos:function>
   <fos:function name="fold-right" prefix="fn">
      <fos:signatures>
         <fos:proto name="fold-right" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="init" type="item()*"/>
            <fos:arg name="action" type="fn(item(), item()*) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Processes the supplied sequence from right to left, applying the supplied function
            repeatedly to each item in turn, together with an accumulated result value.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is empty, the function returns <code>$init</code>.</p>
         <p>Let <var>I/n</var> be the last item in <code>$input</code>, and let <var>A/n</var> be <code>$init</code>.
            The function starts by calling <code>$action(<var>I/n</var>, $init)</code>, producing
         a result <var>A/n-1</var>.</p>
         <p>If there is a previous item, <var>I/n-1</var>,
            the function then calls <code>$action(<var>I/n-1</var>, <var>A/n-1</var>)</code>, producing
            the result <var>A/n-2</var>.</p>
         <p>This continues in the same way until the start of the <code>$input</code> sequence is reached; the final result is
         the value <var>A/0</var>.</p>
         
      </fos:rules>
      <fos:equivalent style="xquery-function">
declare function fold-right(
  $input  as item()*,
  $init   as item()*,
  $action as function(item(), item()*) as item()*
) as item()* {
  if (empty($input))
  then $init
  else $action(head($input), fold-right(tail($input), $init, $action))
};
      </fos:equivalent>
      <fos:errors>
         <p>As a consequence of the function signature and the function calling rules, a type error
            occurs if the supplied function <code>$action</code> cannot be applied to two arguments, where
            the first argument is any item in the sequence <code>$input</code>, and the second is either
            the value of <code>$init</code> or the result of a previous application of
            <code>$action</code>.</p>

      </fos:errors>
      <fos:notes>
         <p>This operation is often referred to in the functional programming literature as
            “folding” or “reducing” a sequence. It takes a function that operates on a pair of
            values, and applies it repeatedly, with the next item in the sequence as the first
            argument, and the result of processing the remainder of the sequence as the second
            argument. The accumulated result is initially set to the value of the <code>$init</code>
            argument, which is conventionally a value (such as zero in the case of addition, one in
            the case of multiplication, or a zero-length string in the case of string concatenation)
            that causes the function to return the value of the other argument unchanged.</p>
         <p>In cases where the function performs an associative operation on its two arguments (such
            as addition or multiplication), <function>fn:fold-right</function> produces the same result as
               <function>fn:fold-left</function>.</p>
         
         
         <p>Unlike other functions that apply a user-supplied callback function to successive
         items in a sequence, this function does not supply the current position to the callback function
         as an optional argument. If positional information is required, this can be achieved by
         first forming the sequence <code>$input ! { 'position': position(), 'item': . }</code>
         and then applying the <function>fn:fold-right</function> function to this sequence.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-right(
  1 to 5,
  0,
  fn($a, $b) { $a + $b }
)</eg></fos:expression>
               <fos:result>15</fos:result>
               <fos:postamble>This returns the sum of the items in the sequence</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-right(
  1 to 5,
  "",
  concat(?, ".", ?)
)</eg></fos:expression>
               <fos:result>"1.2.3.4.5."</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>fold-right(
  1 to 5,
  "$z",
  concat("$f(", ?, ", ", ?, ")")
)</eg></fos:expression>
               <fos:result>"$f(1, $f(2, $f(3, $f(4, $f(5, $z)))))"</fos:result>
            </fos:test>
         </fos:example>
         <!--<fos:example>
            <fos:test>
               <fos:expression><eg>
let $input := (11 to 21, 21 to 31)
let $target := 21
return fold-right(
  $input,
  (),
  action := fn($current, $result, $pos) {
    $result, $pos[$current = $target]
  }
)
</eg></fos:expression>
               <fos:result>12, 11</fos:result>
            </fos:test>
         </fos:example>-->
      </fos:examples>
   </fos:function>
   
       <!--<fos:function name="chain" prefix="fn">
        <fos:signatures>
            <fos:proto name="chain" return-type="item()*">
                <fos:arg name="input" type="item()*"/>
                <fos:arg name="functions" type="fn(*)*"/>
            </fos:proto>
        </fos:signatures>
        <fos:properties>
            <fos:property>deterministic</fos:property>
            <fos:property>context-independent</fos:property>
            <fos:property>focus-independent</fos:property>
        </fos:properties>
        <fos:summary>
           <p>Applies a sequence of functions starting with an initial
              input.</p>
        </fos:summary>
      <fos:rules>
         <p>Informally, the function behaves as follows:</p>
         <olist>
            <item>
               <p>If <code>$functions</code> is empty, then <code>$input</code> is returned,
                  otherwise let <code>$f</code> be the first member of <code>$functions</code>.</p>
            </item>
            <item>
               <p>Let <code>$current-output</code> be the result of <code>fn:apply($f,
                     $input-array)</code> where <code>$input-array</code> is constructed according
                  to the following rules. <olist>
                     <item>
                        <p>If <code>$f</code> has arity 1, let <code>$input-array</code> be an array
                           containing <code>$input</code> as a single member.</p>
                     </item>
                     <item>
                        <p>Otherwise (<code>$f</code> has arity not equal to 1) if <code>$input</code> is
                           not an array then let <code>$input-array</code> be an array containing each
                           item of <code>$input</code> as a separate member. </p>
                     </item>
                     <item>
                        <p>Otherwise (<code>$f</code> has arity not equal to 1<code> and $input</code> is 
                           already an array) let <code>$input-array</code> be <code>$input</code> itself.</p>
                     </item>
                  </olist>
               </p>
            </item>
            <item>
               <p>Repeat the process from step 1, passing <code>$current-output</code> as
                     <code>$input</code> and <code>fn:tail($functions)</code> as
                     <code>$functions</code>.</p>
            </item>
         </olist>
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
let $apply := fn($x, $f)  {
  fn:apply($f,
    if (function-arity($f) eq 1) then [ $x ]
    else if ($x instance of array(*)) then $x 
    else array { $x }
  )
}
return fn($input as item()*, $functions as fn(*)*) as item()* {
  fold-left($functions, $input, $apply)
}                   
      </fos:equivalent>
      <fos:errors>
         <p>An error <errorref class="AP" code="0001" type="type"/> is raised if the arity of any
            function <code>$f</code> in <code>$functions</code> is different from the number of
            members in the array that is passed to <function>fn:apply</function>.</p>
         <p>An error <errorref class="RG" code="0006" type="type"/> is raised if any item supplied as
              a function argument cannot be coerced to the required type.</p>
      </fos:errors>

      <fos:notes>
         <olist>
            <item>
               <p>Functions are applied in sequence order, not right-to-left (as might be expected in
                  mathematical composition).</p>
            </item>
            <item>
               <p>It is not a requirement that every function in <code>$functions</code> must have
                  arity of one. Any function may have any arity. </p>
            </item>
            <item>
               <p>Using <function>fn:chain</function> may result in more readable XPath expressions than
                  chaining expressions using arrow operators.</p>
            </item>
         </olist>
      </fos:notes>
            <fos:examples>
                <fos:variable name="incr" id="chain-variable-incr"
                ><![CDATA[fn($x) { op("+")($x, ?) }]]></fos:variable>
                <fos:variable name="double-all" id="chain-variable-double-all"
                ><![CDATA[fn($nums) { $nums ! op("*")(., 2) }]]></fos:variable>
                <fos:variable name="times" id="chain-variable-times"
                ><![CDATA[fn($y) { op("*")($y,  ?) }]]></fos:variable>
                <fos:variable name="append-all" id="chain-variable-append-all"
                ><![CDATA[fn($strings, $add) { $strings ! concat#2(., $add) }]]></fos:variable>
                <fos:variable name="make-upper-all" id="chain-variable-make-upper-all"
                ><![CDATA[fn($strings) { $strings ! upper-case(.) }]]></fos:variable>
                <fos:variable name="count-all" id="chain-variable-count-all"
                ><![CDATA[fn($ar) { array:for-each($ar, count#1)?* }]]></fos:variable>
                <fos:variable name="product3" id="chain-variable-product3"
                ><![CDATA[fn($x, $y, $z) { $x * $y * $z }]]></fos:variable>
                <fos:variable name="range" id="chain-variable-range"
                ><![CDATA[fn($n) { 1 to $n }]]></fos:variable>
                <fos:example>
                   <fos:test use="chain-variable-incr chain-variable-double-all">
                        <fos:expression>
                            <eg><![CDATA[
chain((2, 3), ($double-all, op("+"), $incr(3)))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>13</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-incr chain-variable-double-all">
                        <fos:expression>
                            <eg><![CDATA[
chain((2, 3), ($double-all, sum#1, $incr(3)))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>13</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-incr">
                        <fos:expression>
                            <eg><![CDATA[
chain((2, 3), (op("+"), $incr(3)))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>8</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-incr">
                        <fos:expression>
                            <eg><![CDATA[
chain((2, 3), (sum#1, $incr(3)))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>8</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-incr">
                        <fos:expression>
                            <eg><![CDATA[
chain([ 1, (), 2, 3 ], (array:size#1, $incr(3)))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>7</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-incr">
                        <fos:expression>
                            <eg><![CDATA[
chain((1, 2, 3), (count#1, $incr(3)))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>6</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-incr">
                        <fos:expression>
                            <eg><![CDATA[
chain([ 1, 2, 3 ], (count#1, $incr(3)))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>4</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-range chain-variable-double-all">
                        <fos:expression>
                            <eg><![CDATA[
chain(5, ($range, $double-all, sum#1))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>30</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-range chain-variable-double-all">
                        <fos:expression>
                            <eg><![CDATA[
chain(2, ($range, $double-all, op("*")))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>8</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-count-all">
                        <fos:expression>
                            <eg><![CDATA[
chain([ (1, 2, 3), () ], ($count-all, op("+")))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>3</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-count-all">
                        <fos:expression>
                            <eg><![CDATA[
chain([ (1, 2, 3), (), (5, 6) ], ($count-all, sum#1))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>5</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-count-all chain-variable-product3">
                        <fos:expression>
                            <eg><![CDATA[
chain([ (1, 2, 3), (), (5, 6) ], ($count-all, $product3))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>0</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test>
                        <fos:expression>
                            <eg><![CDATA[
chain("abra cadabra", (tokenize#2(?, " "), string-join#2(?, "+")))
                                ]]></eg>
                            </fos:expression>
                        <fos:result>"abra+cadabra"</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test use="chain-variable-append-all chain-variable-make-upper-all">
                        <fos:expression>
                            <eg><![CDATA[
chain("The cat sat on the mat", (
  tokenize#2(?, " "), 
  $append-all(?, "."), 
  $make-upper-all, 
  string-join#2(?, " ") 
))]]></eg>
                            </fos:expression>
                        <fos:result>"THE. CAT. SAT. ON. THE. MAT."</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                    <fos:test>
                        <fos:expression>
                            <eg><![CDATA[
chain((
  chain(
    ("A    long   message   ", "   long "), 
    (head#1, normalize-space#1, normalize-unicode#1)
  ),
  chain(
    ("A    long   message   ", "   long "),  
    (tail#1, normalize-space#1, normalize-unicode#1)
  )
  ),
  contains#2
)]]></eg>
                            </fos:expression>
                        <fos:result>true()</fos:result>
                    </fos:test>
                </fos:example>
                <fos:example>
                  <fos:test>
                    <fos:expression>
                       <eg><![CDATA[
chain((), true#0)
    ]]></eg>
                    </fos:expression>
                    <fos:result>true()</fos:result>                   
                  </fos:test>
                </fos:example>
                <fos:example>
                  <fos:test>
                    <fos:expression>
                      <eg><![CDATA[
chain(3, (array:append([1], ?), op("+"))) 
    ]]></eg>
                    </fos:expression>
                    <fos:result>4</fos:result>
                  </fos:test>
                </fos:example>
                <fos:example>
                  <fos:test use="chain-variable-product3">
                    <fos:expression>
                      <eg><![CDATA[
chain((1, 2, 3), ($product3, $product3)) 
    ]]></eg>
                    </fos:expression>
                    <fos:error-result error-code="FOAP0001"/>
                  </fos:test>
                </fos:example>
                <fos:example>
                  <fos:test use="chain-variable-product3">
                    <fos:expression>
                      <eg><![CDATA[
chain((1, 2, 3, 4), $product3) 
    ]]></eg>
                    </fos:expression>
                    <fos:error-result error-code="FOAP0001"/>
                  </fos:test>
                </fos:example>
            </fos:examples>
          <fos:changes>
            <fos:change issue="517" PR="734 1233" date="2022-10-20"><p>New in 4.0</p></fos:change>
          </fos:changes>            
        </fos:function>-->

   <fos:function name="while-do" prefix="fn">
      <fos:signatures>
         <fos:proto name="while-do" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="predicate" type="fn(item()*, xs:integer) as xs:boolean?" example="false#0" usage="inspection"/>
            <fos:arg name="action" type="fn(item()*, xs:integer) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Processes a supplied value repeatedly, continuing while some condition remains true,
            and returning the first value that does not satisfy the condition.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function behaves as follows:</p>
         <olist>
            <item>
               <p><code>$pos</code> is initially set to <code>1</code>.</p>
            </item>
            <item>
               <p><code>$predicate($input, $pos)</code> is evaluated. If the result is
                  <code>false</code> or <code>()</code>, the function returns the value of <code>$input</code>.</p>
            </item>
            <item>
               <p>Otherwise, <code>$action($input, $pos)</code> is evaluated, the resulting value is
                  used as a new <code>$input</code>, and the process repeats from step 2 with
                  <code>$pos</code> incremented by <code>1</code>.</p>
            </item>
         </olist>
      </fos:rules>
      <fos:equivalent style="xquery-function">
declare %private function while-do-helper(
  $input     as item()*,
  $predicate as fn(item()*, xs:integer) as xs:boolean?,
  $action    as fn(item()*, xs:integer) as item()*,
  $pos       as xs:integer
) as item()* {
  if ($predicate($input, $pos))
  then while-do-helper($action($input, $pos), $predicate, $action, $pos + 1)
  else $input
};

declare function while-do(
  $input     as item()*,
  $predicate as fn(item()*, xs:integer) as xs:boolean?,
  $action    as fn(item()*, xs:integer) as item()*
) as item()* {
  while-do-helper($input, $predicate, $action, 1)
};
      </fos:equivalent>
      <fos:notes>
         <p>While-do loops are very common in procedural programming languages, and this function
            provides a way to write functionally clean and interruptible iterations without
            side-effects. As long as a given condition is met, an new value is computed and tested
            again. Depending on the use case, the value can be a simple atomic item or an arbitrarily
            complex data structure.</p>
         <p>The function <function>fn:do-until</function> can be used to perform the action before the
            first predicate test.</p>
         <p>Note that, just as when writing recursive functions, it is easy to construct infinite
            loops.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[while-do(2, fn { . <= 100 }, fn { . * . })]]></eg></fos:expression>
               <fos:result>256</fos:result>
               <fos:postamble>The loop is interrupted as soon as the computed product is greater
                  than 100.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
while-do(
  1,
  fn($num, $pos) { $pos <= 10 },
  fn($num, $pos) { $num * $pos }
)]]></eg></fos:expression>
               <fos:result>3628800</fos:result>
               <fos:postamble>This returns the factorial of 10, i.e., the product of all integers from 1 to 10.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[let $input := (0 to 4, 6 to 10)
return while-do(
  0,
  fn($n) { $n = $input },
  fn($n) { $n + 1 }
)]]></eg></fos:expression>
               <fos:result>5</fos:result>
               <fos:postamble>This returns the first positive number missing in a sequence.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
while-do(
  1 to 9,
  fn($value) { head($value) < 5 },
  fn($value) { tail($value) }
)]]></eg></fos:expression>
               <fos:result>5, 6, 7, 8, 9</fos:result>
               <fos:postamble>The first number of a sequence is removed as long as it is smaller than 5.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
let $input := 3936256
return while-do(
  $input,
  fn($result) { abs($result * $result - $input) >= 0.0000000001 },
  fn($guess) { ($guess + $input div $guess) div 2 }
) => round(5)
]]></eg></fos:expression>
               <fos:result>1984</fos:result>
               <fos:postamble>This computes the square root of a number.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>The following example generates random doubles. It is interrupted once a number
               exceeds a given limit:</p>
            <eg><![CDATA[
let $result := while-do(
  random-number-generator(),
  fn($random) {
    $random?number < 0.8
  },
  fn($random) {
    map:put($random?next(), 'numbers', ($random?numbers, $random?number))
  }
)
return $result?numbers
]]></eg>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="946" PR="962" date="2024-01-23"><p>New in 4.0</p></fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="do-until" prefix="fn">
      <fos:signatures>
         <fos:proto name="do-until" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="action" type="fn(item()*, xs:integer) as item()*" usage="inspection"/>
            <fos:arg name="predicate" type="fn(item()*, xs:integer) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Processes a supplied value repeatedly, continuing when some condition is false,
            and returning the value that satisfies the condition.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function behaves as follows:</p>
         <olist>
            <item>
               <p><code>$pos</code> is initially set to <code>1</code>.</p>
            </item>
            <item>
               <p><code>$action($input, $pos)</code> is evaluated, and the resulting value
                  is used as a new <code>$input</code>.</p>
            </item>
            <item>
               <p><code>$predicate($input, $pos)</code> is evaluated. If the result is
                  <code>true</code>, the function returns the value of <code>$input</code>.
                  Otherwise, the process repeats from step 2 with <code>$pos</code> incremented by
                  <code>1</code>.</p>
               <p>When the predicate returns the empty sequence, this is treated as <code>false</code>.</p>
            </item>
         </olist>
      </fos:rules>
      <fos:equivalent style="xquery-function">
declare %private function do-until-helper(
  $input     as item()*,
  $action    as fn(item()*, xs:integer) as item()*,
  $predicate as fn(item()*, xs:integer) as xs:boolean?,
  $pos       as xs:integer
) as item()* {
  let $result := $action($input, $pos)
  return if ($predicate($result, $pos)) then (
    $result
  ) else (
    do-until-helper($result, $action, $predicate, $pos + 1)
  )
};

declare function do-until(
  $input     as item()*,
  $action    as fn(item()*, xs:integer) as item()*,
  $predicate as fn(item()*, xs:integer) as xs:boolean?
) as item()* {
  do-until-helper($input, $action, $predicate, 1)
};
      </fos:equivalent>
      <fos:notes>
         <p>Do-until loops are very common in procedural programming languages, and this function
            provides a way to write functionally clean and interruptible iterations without
            side-effects. A new value is computed and tested until a given condition fails. Depending
            on the use case, the value can be a simple atomic item or an arbitrarily complex data
            structure.</p>
         <p>The function <function>fn:while-do</function> can be used to perform the action after the
            first predicate test.</p>
         <p>Note that, just as when writing recursive functions, it is easy to construct infinite
            loops.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
do-until(
  (),
  fn($value, $pos) { $value, $pos * $pos },
  fn($value) { foot($value) > 50  }
)
]]></eg></fos:expression>
               <fos:result>1, 4, 9, 16, 25, 36, 49, 64</fos:result>
               <fos:postamble>The loop is interrupted once the last value of the generated sequence
                  is greater than 50.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
do-until(
  (1, 0),
  fn($value) { $value[1] + $value[2], $value },
  fn($value) { avg($value) > 10 }
)
]]></eg></fos:expression>
               <fos:result>55, 34, 21, 13, 8, 5, 3, 2, 1, 1, 0</fos:result>
               <fos:postamble>The computation is continued as long as the average of the first
                  Fibonacci numbers is smaller than 10.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="946" PR="962" date="2024-01-23"><p>New in 4.0</p></fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="for-each-pair" prefix="fn">
      <fos:signatures>
         <fos:proto name="for-each-pair" return-type="item()*">
            <fos:arg name="input1" type="item()*" usage="navigation"/>
            <fos:arg name="input2" type="item()*" usage="navigation"/>
            <fos:arg name="action" type="fn(item(), item(), xs:integer) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Applies the function item <code>$action</code> to successive pairs of items taken one from
               <code>$input1</code> and one from <code>$input2</code>, returning the concatenation of the
            resulting sequences in order.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the value of the expression:</p>
         <eg><![CDATA[
for $pos in 1 to min((count($input1), count($input2)))
return $action($input1[$pos], $input2[$pos], $pos)
]]></eg>
      </fos:rules>
      <fos:notes>
         <p>If one sequence is longer than the other, excess items in the longer sequence are ignored.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>for-each-pair(
  ("a", "b", "c"),
  ("x", "y", "z"),
  concat#2
)</eg></fos:expression>
               <fos:result>"ax", "by", "cz"</fos:result>
            </fos:test>
         </fos:example>
         <!--<fos:example>
            <fos:test>
               <fos:expression><![CDATA[for-each-pair(fn($a, $b) { <e a="{ $a }" b="{ $b }"/> }, (1 to 3), ("x", "y", "z"))]]></fos:expression>
               <fos:result as="element()*"><![CDATA[(<e a="1" b="x"/>, <e a="2" b="y"/>, <e a="3" b="z"/>)]]></fos:result>
               <fos:postamble>This example uses XQuery syntax</fos:postamble>
            </fos:test>
         </fos:example>-->
         <fos:example>
            <fos:test>
               <fos:expression><eg>for-each-pair(
  1 to 5,
  1 to 5,
  fn($a, $b) { 10 * $a + $b }
)</eg></fos:expression>
               <fos:result>11, 22, 33, 44, 55</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $s := 1 to 8
return for-each-pair($s, tail($s), fn($a, $b) { $a * $b })</eg></fos:expression>
               <fos:result>2, 6, 12, 20, 30, 42, 56</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
for-each-pair(
  (1, 8, 2),
  (3, 4, 3),
  fn($item1, $item2, $pos) {
    $pos || ': ' || max(($item1, $item2))
  }
)
]]></eg></fos:expression>
               <fos:result>"1: 3", "2: 8", "3: 3"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="516" PR="828" date="2023-11-14">
            <p>The <code>$action</code> callback function accepts an optional position argument.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="sort" prefix="fn">
      <fos:signatures>
         <fos:proto name="sort" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="collation" type="xs:string?" usage="absorption" default="fn:default-collation()" note="default-on-empty"/>
            <fos:arg name="key" type="fn(item()) as xs:anyAtomicType*" usage="inspection" default="fn:data#1" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
 

      <fos:summary>
         <p>Sorts a supplied sequence, based on the value of a sort key supplied as a function.</p>
      </fos:summary>
      <fos:rules>
         <p>This function is retained for compatibility from version 3.1 of this specification. Version 4.0
         introduces two more powerful functions, <function>fn:sort-by</function> and <function>fn:sort-with</function>.</p>
         
         <p>The function call <code>fn:sort($input, $collation, $key)</code> is defined to have the same effect as the
         call <code>fn:sort-by($input, { 'key': $key, 'collation': $collation, 'order': 'ascending'})</code>.
         See <function>fn:sort-by</function>.</p>
         
         <p>The result of the function is a sequence that contains all the items from <code>$input</code>,
         typically in a different order, the order being defined by the supplied sort key definitions.</p>
         
 
      </fos:rules>
      <fos:equivalent style="xpath-expression">
         fn:sort-by($input, { 'key':$key, 'collation':$collation, 'order':'ascending' })
      </fos:equivalent>
      <fos:errors>
         <p>If the set of computed sort keys contains values that are not comparable using the <code>lt</code> operator then the sort 
            operation will fail with a type error (<xerrorref
               spec="XP" class="TY" code="0004"/>).
         </p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>sort((1, 4, 6, 5, 3))</fos:expression>
               <fos:result>1, 3, 4, 5, 6</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>sort((1, -2, 5, 10, -10, 10, 8), (), abs#1)</fos:expression>
               <fos:result>1, -2, 5, 8, 10, -10, 10</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $SWEDISH := collation({ 'lang': 'se' })
return sort(//name!string(), $SWEDISH)</eg></fos:expression>
               <fos:result narrative="true">The names in <code>//name</code> sorted using Swedish collation.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>sort(//employee, (), fn { name ! (last, first) })</eg></fos:expression>
               <fos:result narrative="true">A sorted sequence of employees by last name as the major sort key and first name as the minor sort key,
               using the default collation.</fos:result>
               <fos:test-assertion>
               <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                  <error code="XPDY0002"/>
               </result>
            </fos:test-assertion>
            </fos:test>           
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="sort-by" prefix="fn">
      <fos:signatures>
         <fos:proto name="sort-by" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="keys" type="record(key? as (fn(item()) as xs:anyAtomicType*)?, collation? as xs:string?, order? as enum('ascending', 'descending')?)*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
 

      <fos:summary>
         <p>Sorts a supplied sequence, based on the value of a number of sort keys supplied as functions.</p>
      </fos:summary>
      <fos:rules>
         <p>The result of the function is a sequence that contains all the items from <code>$input</code>,
         typically in a different order, the order being defined by the supplied <term>sort key definitions</term>.</p>
         
         <p>A <term>sort key definition</term> is a record with three parts:</p>
         
         <olist>
            <item><p><code>key:</code> A <term>sort key function</term>, which is applied to each item in the input sequence to
            determine a <term>sort key value</term>. If no function is supplied, the default is <code>fn:data#1</code>,
            which atomizes the item.</p></item>
            <item><p><code>collation:</code> A <term>collation</term>, which is used when comparing <term>sort key values</term>
               that are of type <code>xs:string</code> or <code>xs:untypedAtomic</code>. If no collation is supplied, the default
               collation from the static context is used.</p>
               <p>When comparing values of types other than <code>xs:string</code> or <code>xs:untypedAtomic</code>,
               the collation is ignored (but an error <rfc2119>may</rfc2119> be reported if it is
               invalid). For more information see <specref ref="choosing-a-collation"/>.</p>
            
            </item>
            <item><p><code>order:</code> An <term>order direction</term>, either <code>"ascending"</code> or
            <code>"descending"</code>. The default is <code>"ascending"</code>.</p></item>
         </olist>
         
         <p>The number of sort key definitions is determined by the number of records supplied
            in the <code>$keys</code> argument. If the argument is absent or empty, the default is
            a single sort key definition using the function <code>data#1</code>, using the default collation
            from the static context, and with order <code>ascending</code>.</p>
         
        
         
        
         <p>The result of the <code>fn:sort-by</code> function is obtained as follows:</p>
         
         <olist>
            <item>
               <p>The result sequence contains the same items as the input sequence <code>$input</code>, 
                  but generally in a different order.</p>
            </item>
            <item>
               <p>The sort key definitions are established as described above.
                  The sort key definitions are in major-to-minor order. That is, the position of two
                  items <code>$A</code> and <code>$B</code> in the result sequence is determined first by the 
                  relative magnitude of their
                  primary sort key values, which are computed by evaluating the <term>sort key function</term> in the 
                  first sort key definition.
                  If those two sort key values are equal, then the position is determined by the relative magnitude
                  of their secondary sort key values, computed by evaluating the 
                  sort key function in the second sort key definition, and so on.</p>              
            </item>
            <item>
               <p>When a pair of corresponding sort key values of <code>$A</code> and <code>$B</code> are 
                  found to be not equal,
                  then <code>$A</code> precedes <code>$B</code> in the result sequence 
                  if both the following conditions are true, or if both conditions are false:</p>
                  <olist>
                     <item>
                        <p>The sort key value for <code>$A</code> is less than the sort key value for <code>$B</code>,
                           as defined below.</p>
                     </item>
                     <item>
                        <p>The <term>order direction</term> in the corresponding sort key definition
                        is <code>"ascending"</code>.</p>
                     </item>
                  </olist>
            </item>
            <item><p>If all the sort key values for <code>$A</code> and <code>$B</code> are pairwise equal, then 
               <code>$A</code> precedes <code>$B</code> in the result sequence if and only if
               <code>$A</code> precedes <code>$B</code> in the input sequence.</p>
               <note><p>That is, the sort is <emph>stable</emph>.</p></note>
            </item>
            <item>
               <p>Each sort key value for a given item is obtained by applying the sort key
               function of the corresponding sort key definition to that item. The result
               of this function is in the general case a sequence of atomic items.
               Two sort key values <code>$a</code> and <code>$b</code> are compared as follows:</p>
               <olist>
                  <item><p>Let <var>$C</var> be the collation in the corresponding
                     sort key definition.</p>
                  </item>
                  <item><p>Let <code>$REL</code> be the result of evaluating <code>op:lexicographic-compare($key($A), $key($B), $C)</code>
                     where <code>op:lexicographic-compare($a, $b, $C)</code> is defined as follows:</p>
                     <eg>if (empty($a) and empty($b)) then 0 
else if (empty($a)) then -1
else if (empty($b)) then +1
else let $rel = op:simple-compare(head($a), head($b), $C)
     return if ($rel eq 0)
            then op:lexicographic-compare(tail($a), tail($b), $C)
            else $rel</eg></item>
                  <item><p>Here <code>op:simple-compare($k1, $k2)</code> is defined as follows:</p>
                     <eg>if ($k1 instance of (xs:string | xs:anyURI | xs:untypedAtomic)
    and $k2 instance of (xs:string | xs:anyURI | xs:untypedAtomic))
then compare($k1, $k2, $C)
else if ($k1 instance of xs:numeric and $k2 instance of xs:numeric)
then compare($k1, $k2)
else if ($k1 eq $k2) then 0
else if ($k2 lt $k2) then -1
else +1</eg>
                     <note><p>This raises an error if two keys are not comparable, for example
                        if one is a string and the other is a number, or if both belong to a non-ordered
                        type such as <code>xs:QName</code>.</p></note></item>
                  <item><p>If <code>$REL</code> is zero, then the two sort key values are deemed
                     equal; if <code>$REL</code> is -1 then <code>$a</code> is deemed less than
                     <code>$b</code>, and if <code>$REL</code> is +1 then <code>$a</code> is deemed greater than
                     <code>$b</code></p></item>
               </olist>
            </item>
         </olist>
      </fos:rules>
      <fos:errors>
         <p>If the set of computed sort keys contains values that are not comparable using the <code>lt</code> operator then the sort 
            operation will fail with a type error (<xerrorref
               spec="XP" class="TY" code="0004"/>).
         </p>
      </fos:errors>
      <fos:notes>
         <p>The function is a generalization of the <function>fn:sort</function> function available in 3.1, 
            which is retained for compatibility. The enhancements allow multiple sort keys to be defined, each potentially with
         a different collation, and allow sorting in descending order.</p>
         <p>If the sort key for an item evaluates to the empty sequence, the effect of the rules is that this item
            precedes any value for which the key is non-empty. This is equivalent to the effect of the XQuery option 
            <code>empty least</code>. The effect of the option <code>empty greatest</code> can be achieved by adding an
            extra sort key definition with <code>{ 'key': fn { empty(K(.) } }</code>: when comparing boolean sort keys,
            <code>false</code> precedes <code>true</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>sort-by((1, 4, 6, 5, 3), ())</fos:expression>
               <fos:result>1, 3, 4, 5, 6</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>sort-by((1, 4, 4e0, 6, 5, 3), { 'order': 'descending' })</fos:expression>
               <fos:result>6, 5, 4, 4e0, 3, 1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>sort-by((1, -2, 5, 10, -10, 10, 8), { 'key': abs#1 })</fos:expression>
               <fos:result>1, -2, 5, 8, 10, -10, 10</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>let $SWEDISH := collation({ 'lang': 'se' })
return sort-by(//name, { 'collation': $SWEDISH })</eg></fos:expression>
               <fos:result narrative="true">The names in <code>//name</code> sorted using Swedish collation.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
            <fos:test>
               <fos:expression><eg>sort-by(//employee, { 'key': fn { name ! (last, first) } })</eg></fos:expression>
               <fos:result narrative="true">Sorts a sequence of employees by last name as the major sort key 
                  and first name as the minor sort key,
               using the default collation</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
            <fos:test>
               <fos:expression><eg>sort-by(
  //employee, 
  ({ 'key': fn { name/last }, 'collation': collation({ 'lang': 'se' }) },
   { 'key': fn { xs:decimal(salary) }, 'order': 'descending' }))</eg></fos:expression>
               <fos:result narrative="true">Sorts a sequence of employees first by increasing last name (using Swedish collation order)
               and then by decreasing salary</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
         
        
      </fos:examples>
      <fos:changes>
         <fos:change issue="1085" PR="2001" date="2025-05-19"><p>New in 4.0.</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="sort-with" prefix="fn">
      <fos:signatures>
         <fos:proto name="sort-with" return-type="item()*">
            <fos:arg name="input" type="item()*"/>
            <fos:arg name="comparators" type="(fn(item(), item()) as xs:integer)+"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Sorts a supplied sequence, according to the order induced by the supplied comparator
            functions.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the items of the supplied <code>$input</code> are sorted into an
            order based on the result of evaluating the supplied <code>$comparators</code>. 
            The result is a sorted sequence.</p>
         <p>Each comparator function takes two items and returns an <code>xs:integer</code> that
            defines the relationship between these items, following the conventions of the
            <function>fn:compare</function> function. Specifically, when a comparator
            <code>$c</code> is used to compare two items <code>$a</code> and <code>$b</code>,
            it must return a negative integer if <code>$a</code> is to be sorted before <code>$b</code>,
            zero if they are considered equal, and a positive integer if <code>$a</code> is
            to be sorted after <code>$b</code>.</p>
         
         <p>There may be more than one comparator, representing sort keys in major to minor order.
         To determine the relative position of two items <code>$a</code> and <code>$b</code>:</p>
         <olist>
            <item><p>The first comparator is called: <code>$comparators[1]($a, $b)</code>. If
            the result is non-zero, this determines the relative position of <code>$a</code>
               and <code>$b</code> in the result sequence, and any further comparators
            can be ignored.</p></item>
            <item><p>If the <var>N</var>th comparator returns zero, then:</p>
               <olist>
                  <item><p>If this is the last comparator, then the two items are considered
                  equal, and their relative position in the result sequence will be the same
                  as their relative position in the input sequence (that is, the sort is
                  <emph>stable</emph>).</p></item>
                  <item><p>Otherwise, the next comparator is evaluated, and so on,
                  until the last comparator is reached or the result of a comparator is non-zero.</p></item>
               </olist>
            </item>
            
         </olist>
         <p>To ensure that the sorting algorithm produces predictable results (indeed, to ensure
         that it terminates), it is necessary for the comparators to have certain properties.
         Specifically, for every comparator <var>C</var>:</p>
         
         <olist>
            <item><p><var>C</var> must be deterministic (if called twice with the same arguments,
            it must deliver the same result).</p></item>
            <item><p>Every item must be equal to itself: <code><var>C</var>($a, $a)</code> must be zero.</p></item>
            <item><p>The ordering must be consistent: if <code><var>C</var>($a, $b) &lt; 0</code>,
            then <code><var>C</var>($b, $a) &gt; 0</code>, and vice versa, and similarly,
            if <code><var>C</var>($a, $b) = 0</code>,
            then <code><var>C</var>($b, $a) = 0</code>.</p></item>
            <item><p>The ordering must be transitive: if <code><var>C</var>($a, $b) &lt; 0</code>
               and <code><var>C</var>($b, $c) &lt; 0</code>, then <code><var>C</var>($a, $c) &lt; 0</code>.</p></item>
         </olist>
         
         
      </fos:rules>
      
      <fos:errors>
         <p>If a comparator function raises an error when processing any pair of items from the input sequence
         (for example, if the comparator function is <code>fn:compare#2</code> and the two items are of
         non-comparable types), then the evaluation of <function>fn:sort-with</function> fails with that
         error.</p> 
         
         <p>In general it is unpredictable which pairs of items from the input sequence
         will actually be compared using each comparator function. However, a comparator function
         <rfc2119>must</rfc2119> not be called to compare two items if they have been determined as unequal by
         an earlier comparator function.</p>
      </fos:errors>

      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>sort-with((1, 4, 6, 5, 3), compare#2)</fos:expression>
               <fos:result>1, 3, 4, 5, 6</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>sort-with((1, 4, 6, 5, 3), op('-'))</fos:expression>
               <fos:result>1, 3, 4, 5, 6</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>sort-with((1, 4, 4e0, 6, 5, 3), fn($a, $b) { compare($b, $a) })</fos:expression>
               <fos:result>6, 5, 4, 4e0, 3, 1</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>sort-with(
  (1, -2, 5, 10, -12, 8),
  fn($a, $b) { abs($a) - abs($b) }
)</eg></fos:expression>
               <fos:result>1, -2, 5, 8, 10, -12</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[
let $persons := <persons>
  <person name='Josipa' age='8'/>
  <person name='Jade' age='6'/>
  <person name='Jie' age='8'/>
</persons>
return sort-with($persons/person, (
  fn($a, $b) { compare($a/@age, $b/@age) },
  fn($a, $b) { compare($a/@name, $b/@name) }
))
]]></eg></fos:expression>
               <fos:result><![CDATA[
<person name="Jade" age="6"/>
<person name="Jie" age="8"/>
<person name="Josipa" age="8"/>]]></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="655 2012" PR="795 2228" date="2024-02-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="transitive-closure" prefix="fn">
      <fos:signatures>
         <fos:proto name="transitive-closure" return-type="gnode()*">
            <fos:arg name="node" type="gnode()?" usage="navigation"/>
            <fos:arg name="step" type="fn(gnode()) as gnode()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns all the GNodes reachable from a given start GNode by applying a supplied function repeatedly.</p>
      </fos:summary>
      <fos:rules>
         
         <p>The function works with both XNodes and JNodes.</p>
         
         <p>The value of <code>$node</code> is a node from which navigation starts. If <code>$node</code> is an
         empty sequence, the function returns the empty sequence.
         </p>
         <p>The value of <code>$step</code> is a function that takes a single GNode as input, and returns a set of GNodes as its result.</p> 
         <p>The result of the <function>fn:transitive-closure</function> function is the set of GNodes that are reachable from
            <code>$node</code> by applying the <code>$step</code> function one or more times.</p>
         
         <p>Although <code>$step</code> may return any sequence of GNodes, the result is treated as a set: the order of GNodes
            in the sequence is ignored, and duplicates are ignored. The result of of the
            <code>transitive-closure</code> function will always be a sequence of GNodes in document order with no duplicates.</p>
      </fos:rules>
      <fos:equivalent style="xquery-function">
declare %private function tc-inclusive(
  $nodes as gnode()*,
  $step  as fn(gnode()) as gnode()*
) as gnode()* {
  let $nextStep := $nodes/$step(.)
  let $newNodes := $nextStep except $nodes
  return if (exists($newNodes))
         then $nodes union tc-inclusive($newNodes, $step)
         else $nodes
};

declare function transitive-closure (
  $node as gnode(),
  $step as fn(gnode()) as gnode()*
) as gnode()* {
  tc-inclusive($node/$step(.), $step)
};

(: Explanation:

   The private helper function tc-inclusive takes a set of GNodes as input,
   and calls the $step function on each one of those GNodes; if the result 
   includes GNodes that are not already present in the input, then it makes 
   a recursive call to find GNodes reachable from these new GNodes, and returns
   the union of the supplied GNodes and the GNodes returned from the recursive
   call (which will always include the new GNodes selected in the first step).
   
   If there are no new GNodes, the recursion ends, returning the GNodes that 
   have been found up to this point.
   
   The main function fn:transitive-closure finds the nodes that are reachable 
   from the start GNodes in a single step, and then invokes the helper function 
   tc-inclusive to add GNodes that are reachable in multiple steps.
:)   
      </fos:equivalent>
      <fos:notes>
         <p>Cycles in the data are not a problem; 
            the function stops searching when it finds no new GNodes.</p>
         <p>The function may fail to terminate if the supplied <code>$step</code> function constructs and returns
         new GNodes. A processor <rfc2119>may</rfc2119> detect this condition but is not required to do so.</p>
         <p>The <code>$node</code> GNodes is not included in the result, unless it is reachable by applying
         the <code>$step</code> function one or more times. If a result is required that does include <code>$node</code>,
         it can be readily added to the result using the union operator:
            <code>$node | transitive-closure($node, $step)</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="data" id="transitive-closure-data"><![CDATA[document { <doc>
  <person id="0"/>
  <person id="1" manager="0"/>
  <person id="2" manager="0"/>
  <person id="3" manager="2"/>
  <person id="4" manager="2"/>
  <person id="5" manager="1"/>
  <person id="6" manager="3"/>
  <person id="7" manager="6"/>
  <person id="8" manager="6"/>
</doc> }]]>
         </fos:variable>
         <fos:variable name="direct-reports" id="transitive-closure-reports"><![CDATA[fn($p as element(person)) as element(person)* {
  $p/../person[@manager = $p/@id]
}]]>
         </fos:variable>          
         <fos:example>
            <fos:test use="transitive-closure-data transitive-closure-reports" spec="XQuery">
               <fos:expression><eg>transitive-closure(
  $data//person[@id = "2"],
  $direct-reports
)/string(@id)</eg></fos:expression>
               <fos:result>"3", "4", "6", "7", "8"</fos:result>
            </fos:test>            
            <fos:test use="transitive-closure-data" spec="XQuery">
               <fos:expression><eg>transitive-closure(
  $data, 
  function { child::* }
)/@id ! string()</eg></fos:expression>
               <fos:result>"0", "1", "2", "3", "4", "5", "6", "7", "8"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>The following example, given <code>$root</code> as the root of an XSLT stylesheet module, returns the URIs
            of all stylesheet modules reachable using <code>xsl:import</code> and <code>xsl:include</code> declarations:</p>
            <eg>transitive-closure($root, fn { document(//(xsl:import|xsl:include)/@href) }) 
=!> document-uri()</eg>
            <p>This example uses the XSLT-defined <code>document()</code> function.</p>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="518 554 754" PR="521 761" date="2023-10-18"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="apply" prefix="fn">
      <fos:signatures>
         <fos:proto name="apply" return-type="item()*">
            <fos:arg name="function" type="fn(*)" usage="inspection"/>
            <fos:arg name="arguments" type="array(*)" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Makes a dynamic call on a function with an argument list supplied in the form of an array.</p>
      </fos:summary>
      <fos:rules>
         <p>The result of the function is obtained by invoking the supplied function <code>$function</code> with arguments
         taken from the members of the supplied array <code>$arguments</code>. The first argument of the function call is the first
         member of <code>$arguments</code>, the second argument is the second member of <code>$arguments</code>, and so on.</p>
         <p>The arity of the supplied function <code>$function</code> must be less than or equal to the size 
            of the array <code>$arguments</code>.</p>
         <p>The effect of calling <code>fn:apply($f, [$a, $b, $c, ...])</code> is the same as the effect of the dynamic function call 
            <code>$f($a, $b, $c, ....)</code>. For example, the coercion rules are applied to the supplied arguments
            in the usual way. Among other things this means that excess arguments are ignored.</p>
      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised if the arity of the function <code>$function</code> is greater than the size of the
            array <code>$arguments</code> (<errorref
               spec="FO" class="AP" code="0001"/>).
         </p>
      </fos:errors>
      <fos:notes>
         <p>The function is useful where the arity of a function item is not known statically.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>apply(concat#3, [ "a", "b", "c" ])</fos:expression>
               <fos:result>"abc"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>The expression <code>apply($f, array:subarray([ "a", "b", "c", "d", "e", "f" ], 1, function-arity($f)))</code> 
               calls the supplied function <code>$f</code> supplying the number of arguments required by its arity.</p>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1267" PR="1280" date="2024-06-18">
            <p>As a result of changes to the coercion rules, the number of supplied
         arguments can be greater than the number required: extra arguments are ignored.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="partial-apply" prefix="fn">
      <fos:signatures>
         <fos:proto name="partial-apply" return-type="fn(*)">
            <fos:arg name="function" type="fn(*)" usage="inspection"/>
            <fos:arg name="arguments" type="map(xs:positiveInteger, item()*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Performs partial application of a function item by binding values to selected arguments.</p>
      </fos:summary>
      <fos:rules>
         <p>The result is a function obtained by binding values to selected arguments of 
            the function item <code>$function</code>. The arguments to be bound are represented
            by entries in the <code>$arguments</code> map: an entry with key <code>$i</code>
            and value <code>$v</code> causes the argument at position <code>$i</code> (1-based)
            to be bound to <code>$v</code>.
         </p>
         <p>Any entries in <code>$arguments</code> whose keys are greater than the arity of
         <code>$function</code> are ignored.</p>
         
         <p>If <code>$arguments</code> is the empty map then the function returns <code>$function</code>
         unchanged.</p>
         
         <p>For example, the effect of calling <code>fn:partial-apply($f, { 2: $x })</code>
            is the same as the effect of the partial 
            appplication <code>$f(?, $x, ?, ?, ....)</code>. 
            The coercion rules are applied to the supplied arguments
            in the usual way.</p>
         
         <p>Unlike a partial application using place-holder arguments:</p>
         
         <ulist>
            <item><p>The arity of <code>$function</code> need not be statically known.</p></item>
            <item><p>It is possible to bind all the arguments of <code>$function</code>: the effect
               is to return a zero-arity function.
          </p></item>
         </ulist>
         
          <p>The result is a <xtermref spec="XP40"
                           ref="dt-partially-applied-function"
                           >partially applied function</xtermref> having
                        the following properties (which are defined in <xspecref
                           spec="DM40" ref="function-items"/>):
                     </p>
                     <ulist>
                        <item>
                           <p><term>name</term>: absent.
                           </p>
                        </item>
                        <item><p><term>identity</term>: A new function
                           identity distinct from the identity of any other function item.</p>
                           <note><p>See also <xspecref spec="XP40" ref="id-function-identity"/>.</p></note>
                        </item>
                        <item>
                           <p><term>arity</term>: The arity of <code>$function</code> minus the
                              number of parameters in <code>$function</code> that map to supplied
                              arguments in <code>$arguments</code>.</p>
                        </item>
                        <item>
                           <p>
                              <term>parameter names</term>:
                              The names of the parameters of <code>$function</code>
                              that do not map to supplied
                              arguments in <code>$arguments</code>.
                           </p>

                        </item>
                        
                        <item>
                           <p>
                              <term>signature</term>: The parameters in the returned function
                              are the parameters of <code>$function</code>
                              that do not map to supplied
                              arguments in <code>$arguments</code>,
                              retaining order. The result type of the returned function
                              is the same as the result type of <code>$function</code>.</p>
                              
                              <p>An implementation that can determine a more specific signature (for example, 
                              through use of type analysis) is permitted to do so.
                           </p>
                        </item>
                        
                        <item>
                           <p><term>body</term>: The body of <code>$function</code>.</p>
                        </item>
                        
                        <item>
                           <p>
                              <term>captured context</term>: The
                              static and dynamic context of <code>$function</code>, augmented,
                              for each supplied argument, with
                              a binding of the converted argument value
                              to the corresponding parameter name.
                           </p>
                        </item>
                     </ulist>
      </fos:rules>
      <fos:errors>
         <p>A type error is raised if any of the supplied arguments, 
         after applying the coercion rules, does not match the required type of the corresponding function 
         parameter.</p>
         <p>In addition, a dynamic error may be raised if any of the supplied arguments does not match 
            other constraints on the value of that argument (for example, if the value supplied 
            for a parameter expecting a regular expression is not a valid regular expression); 
            or if the processor is able to establish that evaluation of the resulting function 
            will fail for any other reason (for example, if an error is raised while evaluating 
            a subexpression in the function body that depends only on explicitly supplied 
            and defaulted parameters).</p>
      </fos:errors>
      <fos:notes>
         <p>See also <xspecref spec="XP40" ref="id-partial-function-application"/>.</p>
         <p>The function is useful where the arity of a function item is not known statically,
         or where all arguments in a function are to be bound, returning a zero-arity function.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
let $f := partial-apply(dateTime#2,  {2: xs:time('00:00:00') })
return $f(xs:date('2025-03-01'))</eg></fos:expression>
               <fos:result>xs:dateTime('2025-03-01T00:00:00')</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1816" PR="1825" date="2025-02-25">
            <p>New in 4.0</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="op" prefix="fn">
      <fos:signatures>
         <fos:proto name="op" return-type="fn(item()*, item()*) as item()*">
            <fos:arg name="operator" type="xs:string"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns a function whose effect is to apply a supplied binary operator to two arguments.</p>
      </fos:summary>
      <fos:rules>
         <p>The supplied operator must be one of:</p>
         <p><code>","</code>, <code>"and"</code>, <code>"or"</code>, <code>"+"</code>,
            <code>"-"</code>, <code>"*"</code>, <code>"div"</code>, <code>"idiv"</code>,
            <code>"mod"</code>, <code>"="</code>, <code>"&lt;"</code>, <code>"&lt;="</code>,
            <code>"&gt;"</code>, <code>">="</code>, <code>"!="</code>, <code>"eq"</code>,
            <code>"lt"</code>, <code>"le"</code>, <code>"gt"</code>, <code>"ge"</code>,
            <code>"ne"</code>, <code>"&lt;&lt;"</code>, <code>"&gt;&gt;"</code>,
            <code>"precedes"</code>, <code>"follows"</code>, <code>"precedes-or-is"</code>, <code>"follows-or-is"</code>,
            <code>"is"</code>, <code>"is-not"</code>, <code>"||"</code>, <code>"|"</code>, <code>"union"</code>,
            <code>"except"</code>, <code>"intersect"</code>, <code>"to"</code>,
            <code>"otherwise"</code>.</p>
         <p>The result of calling <code>fn:op("⊙")</code>, where <code>⊙</code> is one of the above operators, is
         the function represented by the XPath expression:</p>
         <p><code>fn($x, $y) { $x ⊙ $y }</code></p>
         <p>For example, <code>op("+")</code> returns <code>fn($x, $y) { $x + $y }</code>.</p>
      </fos:rules>
      <fos:errors>
         <p>A type error is raised <xerrorref spec="XP" class="TY" code="0004" type="type"/> if the
            supplied argument is not one of the supported operators.
         </p>
      </fos:errors>
      <fos:notes>
         <p>The function is useful in contexts where an arity-2 callback function needs to be supplied, and
            a standard operator meets the requirement.</p>
         <p>For example, the XSLT <code>xsl:map</code> instruction
            has an <code>on-duplicates</code> attribute that expects such a function. Specifying
         <code>on-duplicates="op(',')"</code> is equivalent to specifying 
         <code>on-duplicates="fn($x, $y) { $x, $y }</code></p>
         <p>The function is also useful in cases where the choice of operator to apply is
         made dynamically.</p>
         <p>Some operators (such as <code>and</code>, <code>or</code>, and <code>otherwise</code>)
         have custom error handling semantics, with the effect that evaluating one of the operands cannot
         cause an error unless the other operand has a particular value 
         (see <xspecref spec="XP40" ref="id-guarded-expressions"/>). Although implementations are free
         to make optimizations, it should be assumed that a function call such as <code>op('and')(X, Y)</code>
         will have the normal semantics of a dynamic function call, where the arguments are evaluated in any order,
         and a failure evaluating any argument may cause the function call as a whole to fail.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>for-each-pair(21 to 25, 1 to 5, op("+"))</fos:expression>
               <fos:result>22, 24, 26, 28, 30</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>for-each-pair(21 to 25, 1 to 5, op("-"))</fos:expression>
               <fos:result>20, 20, 20, 20, 20</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="83" PR="173" date="2022-10-11"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="atomic-type-annotation" prefix="fn">
      <fos:signatures>
         <fos:proto name="atomic-type-annotation" return-type-ref="schema-type-record">
            <fos:arg name="value" type="xs:anyAtomicType"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>        
      </fos:properties>
      <fos:summary>
         <p>Returns a record containing information about the type annotation of an atomic value.</p>
      </fos:summary>
      <fos:rules>        
         <p>Given an atomic value, the function returns a <loc href="#schema-type-record">schema-type-record</loc>
         containing information about the atomic type represented by its <xtermref spec="DM40" ref="dt-type-annotation"/>.</p>
      </fos:rules>
      <fos:notes>
         <p>The result will always have <code>?is-simple = true()</code> and <code>?variety = "atomic"</code>. In a non-schema-aware
         environment the type will always be a built-in atomic type in the <code>xs</code> namespace: see
         <specref ref="atomic-type-hierarchy"/>. Where a schema is in use, however, the result may be an atomic type defined
         in the schema, which may be an anonymous type.</p>
         
         <p>Note that under the function coercion rules, it is possible to supply a node as the argument, which
         will then be atomized. In simple cases the type annotation on the atomized value will be the same as
         the type annotation on the node. But this is not always true: for example the type annotation on
         the node might be a complex type with simple content, while the type annotation on its atomized
         value is the corresponding simple content type. To get the type annotation on the node, use the function
         <function>fn:node-type-annotation</function>.</p>
         
         <p>This function should not be used as a substitute for an <code>instance of</code> test. The precise type annotation
         of the result of an expression is not always predictable, because processors are free to deliver a more specific type
         than is mandated by the specification. For example, if <code>$n</code> is of type <code>xs:positiveInteger</code>,
         then the result of <code>abs($n)</code> is guaranteed to be an instance of <code>xs:integer</code>, but an 
         implementation might reasonably return the supplied value unchanged: that is, a value whose actual type 
         annotation is <code>xs:positiveInteger</code>. Similarly the type annotation of the value returned by
         <code>position()</code> might be <code>xs:long</code> rather than <code>xs:integer</code>.</p>
         
         <p>Implementations <rfc2119>should</rfc2119>, however, refrain from exposing types that are purely internal.
         For example, an implementation might have an optimized internal representation for strings consisting entirely
         of ASCII characters, or for single-character strings; if this is the case then the type annotation returned by this function
         should be a user-visible supertype such as <code>xs:string</code>.</p>
      </fos:notes>
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression><eg>atomic-type-annotation(23) ? name</eg></fos:expression>
               <fos:result>#xs:integer</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $x := 23, $y := 93.7 
return atomic-type-annotation($x) ? matches($y)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>atomic-type-annotation(xs:numeric('23.2')) ? name</eg></fos:expression>
               <fos:result>#xs:double</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="148" PR="1523" date="2024-10-22"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="node-type-annotation" prefix="fn">
      <fos:signatures>
         <fos:proto name="node-type-annotation" return-type-ref="schema-type-record">
            <fos:arg name="node" type="(element() | attribute())" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns a record containing information about the type annotation of an element or attribute node.</p>
      </fos:summary>
      <fos:rules>        
         <p>Given an element or attribute node, the function returns a <loc href="#schema-type-record">schema-type-record</loc>
         containing information about the schema type represented by its <xtermref spec="DM40" ref="dt-type-annotation"/>.</p>
         
      </fos:rules>
      <fos:notes>
         <p>For an element that has not been schema-validated, the type annotation is always <code>xs:untyped</code>.</p>
         <p>For an attribute that has not been schema-validated, the type annotation is always <code>xs:untypedAtomic</code>.</p>
         <p>The type annotation of an attribute node is always a simple type; the type annotation of an element node may
         be simple or complex.</p>
      </fos:notes>
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[let $e := parse-xml("<e/>")/*
return node-type-annotation($e) ? name]]></eg></fos:expression>
               <fos:result>#xs:untyped</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[let $a := parse-xml("<e a='3'/>")//@a
return node-type-annotation($a) ? name]]></eg></fos:expression>
               <fos:result>#xs:untypedAtomic</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test schema-aware="true">
               <fos:expression><eg><![CDATA[let $x := json-to-xml('[23, 24]', { 'validate': true() })
return node-type-annotation($x/*) ? name]]></eg></fos:expression>
               <fos:result>#fn:arrayType</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test schema-aware="true">
               <fos:expression><eg><![CDATA[let $x := json-to-xml('[23, 24]', { 'validate': true() })
let $n23 := $x//fn:number[. = 23]                  
let $type := node-type-annotation($n23)
return ($type ? name, 
        $type ? base-type() ? name, 
        $type ? base-type() ? base-type() ? name)]]></eg></fos:expression>
               <fos:result><eg>#fn:numberType, 
#fn:finiteNumberType, 
#xs:double</eg></fos:result>
            </fos:test>
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="148" PR="1523" date="2024-10-22"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="schema-type" prefix="fn">
      <fos:signatures>
         <fos:proto name="schema-type" return-type-ref="schema-type-record" return-type-ref-occurs="?">
            <fos:arg name="name" type="xs:QName"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns a record containing information about a named schema type in the static context.</p>
      </fos:summary>
      <fos:rules>        
         <p>If the static context (specifically, the <xtermref spec="XP40" ref="dt-is-types">in-scope schema types</xtermref>) 
            includes a schema type whose name matches <code>$name</code>, 
            the function returns a <loc href="#schema-type-record">schema-type-record</loc>
         containing information about that schema type. If not, it returns the empty sequence.</p>
      </fos:rules>
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression>schema-type( #xs:integer ) ? name</fos:expression>
               <fos:result>#xs:integer</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>schema-type( #xs:long ) ? primitive-type() ? name</fos:expression>
               <fos:result>#xs:decimal</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>schema-type( #xs:positiveInteger ) ? base-type() ? name</fos:expression>
               <fos:result>#xs:nonNegativeInteger</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>schema-type( #xs:integer ) ? matches(23)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>schema-type( #xs:numeric ) ? variety</fos:expression>
               <fos:result>"union"</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>schema-type( #xs:numeric ) ? members() ? name</fos:expression>
               <fos:result>#xs:double, #xs:float, #xs:decimal</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="148" PR="1523" date="2024-10-22"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="atomic-equal" prefix="fn">
      <fos:signatures>
         <fos:proto name="atomic-equal" return-type="xs:boolean">
            <fos:arg name="value1" type="xs:anyAtomicType"/>
            <fos:arg name="value2" type="xs:anyAtomicType"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Determines whether two atomic items are equal, under the rules used for comparing keys in a map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>fn:atomic-equal</function> is used to compare two atomic items for equality. This function
         has the following properties (which do not all apply to the <code>eq</code> operator):</p>
         <ulist>
            <item><p>Any two atomic items can be compared, regardless of their type.</p></item>
            <item><p>No dynamic error is ever raised (the result is either <code>true</code> or <code>false</code>).</p></item>
            <item><p>The result of the comparison never depends on the static or dynamic context.</p></item>
            <item><p>Every value (including <code>NaN</code>) is equal to itself.</p></item>
            <item><p>The comparison is symmetric: if <var>A</var> equals <var>B</var>, then <var>B</var> equals <var>A</var>.</p></item>
            <item><p>The comparison is transitive: if <var>A</var> equals <var>B</var> and <var>B</var> equals <var>C</var>,
               then <var>A</var> equals <var>C</var>.</p></item>
         </ulist>
         
         <p>The function returns <code>true</code> if and only if one of the following conditions is true:</p>

         <olist>
            <item>
               <p>All of the following conditions are true:</p>
               <olist>
                  <item>
                     <p><code>$value1</code> is an instance of <code>xs:string</code>, <code>xs:anyURI</code>, or <code>xs:untypedAtomic</code></p>
                  </item>
                  <item>
                     <p><code>$value2</code> is an instance of <code>xs:string</code>, <code>xs:anyURI</code>, or <code>xs:untypedAtomic</code></p>
                  </item>
                  <item>
                     <p>
                        <code>fn:codepoint-equal($value1, $value2)</code>
                     </p>
                  </item>
               </olist>
               <note>
                  <p>Strings are compared without any dependency on collations.</p>
               </note>
            </item>
            <item>
               <p>All of the following conditions are true:</p>
               <olist>
                  <item>
                     <p><code>$value1</code> is an instance of <code>xs:decimal</code>, <code>xs:double</code>, or <code>xs:float</code></p>
                  </item>
                  <item>
                     <p><code>$value2</code> is an instance of <code>xs:decimal</code>, <code>xs:double</code>, or <code>xs:float</code></p>
                  </item>
                  <item>
                     <p><code>fn:compare($value1, $value2)</code> returns zero.</p>
                  
                     <note><p><code>NaN</code> is equal to <code>NaN</code>, <code>INF</code>
                     is equal to <code>INF</code>, <code>-INF</code> is equal to <code>-INF</code>,
                     positive zero equals negative zero. This applies both to <code>xs:double</code>
                     amd <code>xs:float</code> values, including comparisons across these two types.</p>
      
                     
                        <p>Ordinary values (numeric values other than the special values mentioned above)
                           are compared according to their mathematical magnitude. 
                           Every instance of <code>xs:double</code>, <code>xs:float</code>, and <code>xs:decimal</code> can be represented
                              exactly as a decimal number provided enough digits are available both before and after the decimal point.
                              This comparison is therefore transitive.</p>
                           
                     </note>
                  </item>
                  
            <item>
               <p>All of the following conditions are true:</p>
               <olist>
                  <item>
                     <p>One of the following conditions is true:</p>
                     <olist>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:date</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:time</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:dateTime</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:gYear</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:gYearMonth</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:gMonth</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:gMonthDay</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:gDay</code>.</p></item>
                     </olist>
                  </item>
                  <item>
                     <p>One of the following conditions is true:</p>
                     <olist>
                        <item>
                           <p>Both <code>$value1</code> and <code>$value2</code> have a timezone</p>
                        </item>
                        <item>
                           <p>Neither <code>$value1</code> nor <code>$value2</code> has a timezone</p>
                        </item>
                     </olist>
                  </item>
                  <item>
                     <p>
                        <code>fn:compare($value1, $value2)</code> returns zero.
                     </p>
                  </item>

               </olist>
               <note><p>Values having a timezone are never equal to values without one. The implicit timezone is not used.</p></note>
               
            </item>
            
            <item>
               <p>All of the following conditions are true:</p>
               <olist>
                  <item>
                     <p><code>$value1</code> is an instance of <code>xs:hexBinary</code> or <code>xs:base64Binary</code></p>
                  </item>
                  <item>
                     <p><code>$value2</code> is an instance of <code>xs:hexBinary</code> or <code>xs:base64Binary</code></p>
                  </item>
                  <item>
                     <p><code>fn:compare($value1, $value2)</code> returns zero.</p>
                  </item>
               </olist>
            </item>
            <item>
               <p>All of the following conditions are true:</p>
               <olist>
                  <item>
                     <p>One of the following conditions is true:</p>
                     <olist>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:boolean</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:QName</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:NOTATION</code>.</p></item>
                        <item><p><code>$value1</code> and <code>$value2</code> are both instances of <code>xs:duration</code>.</p></item>
                     </olist>
                  </item>

                  <item>
                     <p>
                        <code>fn:compare($value1, $value2)</code> returns zero.
                     </p>
                  </item>
               </olist>
            </item>
            
         </olist>
            </item></olist>    
      </fos:rules>

      <fos:notes>
         <p>The internal function <code role="example">op:same-key</code> was introduced in an earlier version of this specification
            for comparing keys within a map.
            In this version of the specification, the functionality is unchanged, but the function is exposed so that it
            is available directly to applications.</p>
         
         <p>The function is used to assess whether two atomic
            items are considered to be duplicates when used as keys in a map. A map cannot
            contain two separate entries whose keys are <term>the same</term> as defined by this function. 
            The function is also used when matching keys in functions such as <function>map:get</function>
            and <function>map:remove</function>.</p>
         
         <p>The rules for comparing keys in a map are chosen to ensure that the comparison is:</p>
         <ulist>
            <item>
               <p><term>Context-free</term>: there is no dependency on the static or dynamic context</p>
            </item>
            <item>
               <p><term>Error-free</term>: any two atomic items can be compared, and the result is either <code>true</code> or <code>false</code>, never an error</p>
            </item>
            <item>
               <p><term>Transitive</term>: if <var>A</var> is the same key as <var>B</var>, and <var>B</var> is the same key as <var>C</var>, 
               then <var>A</var> is the same key as <var>C</var>.</p>
            </item>
         </ulist>
         <p>Two atomic items may be distinguishable even though they are equal under this comparison. For example: they may have
         different type annotations; dates and times may have different timezones; <code>xs:QName</code> values may have different
         prefixes.</p>
         <p>Unlike previous versions of this specification, <code>xs:hexBinary</code> and
         <code>xs:base64Binary</code> values are mutually comparable. This decision affects backwards
         compatibility: it is no longer possible to construct certain maps that
         could be validly constructed using earlier versions of the specification. This may also cause problems
         passing data from a 3.1 processor to a 4.0 processor.</p>
         <p>As always, any algorithm that delivers the right result is acceptable. For example, when testing whether an <code>xs:double</code>
         value <var>D</var> is the same key as an <code>xs:decimal</code> value that has <var>N</var> significant digits, it is not
         necessary to know all the digits in the decimal expansion of <var>D</var> to establish the result: computing the first <var>N+1</var> 
            significant digits (or indeed, simply knowing that there are more than <var>N</var> significant digits) is sufficient.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>atomic-equal("a", "a")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal("a", "A")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal("a", xs:untypedAtomic("a"))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>atomic-equal(
  "https://www.w3.org/",
  xs:anyURI("https://www.w3.org/")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(3, 3)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(3, 3e0)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(3.1, 3.1e0)</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(xs:double('NaN'), xs:float('NaN'))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>           
            <fos:test>
               <fos:expression>atomic-equal(12, "12")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(xs:time('16:00:00Z'), xs:time('17:00:00+01:00'))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(xs:time('16:00:00Z'), xs:time('16:00:00'))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(xs:duration('PT1H'), xs:duration('PT60M'))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(xs:duration('PT0S'), xs:duration('P0Y'))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(xs:duration('P30D'), xs:duration('P1M'))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(#Q{http://example.com}name, #Q{http://example.com}prefix:name)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>atomic-equal(xs:hexBinary(""), xs:base64Binary(""))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="221" PR="319" date="2023-02-01"><p>New in 4.0. The function replaces the internal <code>op:same-key</code>
         function in 3.1</p></fos:change>

         <fos:change issue="2139" PR="2168" date="2025-08-19"><p>Atomic items of types <code>xs:hexBinary</code> 
            and <code>xs:base64Binary</code> are now mutually comparable. In rare cases, where an
            application uses both types and assumes they are distinct, this can represent a backwards
            incompatibility.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="merge" prefix="map">
      <fos:signatures>
         <fos:proto name="merge" return-type="map(*)">
            <fos:arg name="maps" type="map(*)*" usage="inspection"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a map that combines the entries from a number of existing maps.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:merge</function>
            returns a map that is formed by combining the contents of the maps supplied in the <code>$maps</code>
            argument.</p>


         <p>Informally, the supplied maps are combined as follows:</p>

         <olist>
            <item>
               <p>There is one entry in the returned map for each distinct key present in the union
                  of the input maps, where two keys are distinct if they are not the <termref
                        def="dt-same-key">same key</termref>. The order of the input maps,
               and of the entries within these input maps, is retained in the 
               <xtermref spec="DM40" ref="dt-entry-order"/> of the result map.</p>
            </item>
            <item>
               <p>If there are duplicate keys, that is, if two or more maps contain entries having the
                  <termref
                     def="dt-same-key"
                     >same key</termref>, then the relevant entries are combined in a way
                   that is controlled by the supplied <code>$options</code>.</p>
            
         
               <p>The <code>$options</code> argument takes the same values (with the same meanings)
               as the <function>map:build</function> function, except that the default is different:
               for <code>map:merge</code>, the default for duplicate keys is <code>use-first</code>.</p>
               
               <note><p>The difference is for backwards compatibility reasons.</p></note>
               
               <p>With the default options, when duplicate entries occur:</p>
               
               <olist>
                  <item><p>There will be a single entry in the result 
                     corresponding to a set of duplicate entries in the input.
                  </p></item>
                  <item><p>The value of that entry will be taken from the first
                  of the duplicates.</p></item>
                  <item><p>The position of that entry in the <xtermref spec="DM40"
                  ref="dt-entry-order"/> of the result map will correspond to the
                  position of the first of the duplicates.</p></item>
                  <item><p>The key of the combined entry 
                  will correspond to the key of one of the duplicates: it is
                  <termref def="implementation-dependent"/> which one is chosen. (Keys may be 
                  duplicates even though they differ: for example, they may have
                  different type annotations, or they may be <code>xs:dateTime</code>
                  values in different timezones.)</p></item>
               </olist>

           </item>

         </olist>

      </fos:rules>
 <!--     <fos:equivalent style="xpath-expression">
map:of-pairs(
  $maps =!> map:pairs(), 
  $options[exists(?duplicates)] otherwise { "duplicates": "use-first" }
)
      </fos:equivalent>-->
     
      <fos:errors>

         
         <p>An error is raised <errorref spec="FO" class="JS" code="0003"
               /> if the value of 
          <code>$options</code> indicates that duplicates are to be rejected, and a duplicate key is encountered.</p>
         <p>An error is raised <errorref spec="FO" class="JS" code="0005"
               /> if the value of 
          <code>$options</code> includes an entry whose key is defined 
          in this specification, and whose value is not a permitted value for that key.</p>
         
      </fos:errors>

      <fos:notes>
         

         <p>If the input is the empty sequence, the result is the empty map.</p>
         <p>If the input is a sequence of length one, the result map is 
            indistinguishable from the input map.</p>
         <p>There is no requirement that 
            the supplied input maps should have the same or compatible
            types. The type of a map (for example <code>map(xs:integer, xs:string)</code>) is
            descriptive of the entries it currently contains, but is not a constraint on how the map
            may be combined with other maps.</p>
         <p>The XSLT 3.0 recommendation included a specification of this function that incorrectly used
            the option value <code>{ 'duplicates': 'unspecified' }</code> in place of
            <code>{ 'duplicates': 'use-any' }</code>. XSLT implementations wishing to
            preserve backwards compatibility <rfc2119>may</rfc2119> choose to retain support
            for this setting.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="week" id="v-map-merge-week"
            select="{&#xa;  0: &quot;Sonntag&quot;, 1: &quot;Montag&quot;, 2: &quot;Dienstag&quot;, 3: &quot;Mittwoch&quot;,&#xa;  4: &quot;Donnerstag&quot;, 5: &quot;Freitag&quot;, 6: &quot;Samstag&quot;&#xa;}"/>
         <fos:example>
            <fos:test>
               <fos:expression>map:merge(())</fos:expression>
               <fos:result>{}</fos:result>
               <fos:postamble>Returns the empty map</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:merge((
  map:entry(0, "no"),
  map:entry(1, "yes")
))</eg></fos:expression>
               <fos:result>{ 0: "no", 1: "yes" }</fos:result>
               <fos:postamble>Returns a map with two entries</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:merge(({ "red": 0 }, { "green": 1}, { "blue": 2 })) 
=> map:keys()</eg></fos:expression>
               <fos:result>"red", "green", "blue"</fos:result>
               <fos:postamble>Note the order of the result.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-merge-week">
               <fos:expression><eg>map:merge(
  ($week, { 7: "Unbekannt" })
)</eg></fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag", 7: "Unbekannt" }</eg></fos:result>
               <fos:postamble>The value of the existing map is unchanged; the <phrase>returned map 
                  contains</phrase> all the entries from <code>$week</code>, supplemented with an additional
                  entry.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-merge-week">
               <fos:expression><eg>map:merge(
  ($week, { 6: "Sonnabend" }),
  { "duplicates": "use-last" }
)</eg></fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Sonnabend" }</eg></fos:result>
               <fos:postamble>The value of the existing map is unchanged; the returned map
                  contains all the entries from <code>$week</code>, with one entry replaced by a
                  new entry. Both input maps contain an entry with the key <code>6</code>; the
                  one used in the result is the one that comes last in the input
                  sequence.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-merge-week">
               <fos:expression><eg>map:merge(
  ($week, { 6: "Sonnabend" }),
  { "duplicates": "use-first" }
)</eg></fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag" }</eg></fos:result>
               <fos:postamble>The value of the existing map is unchanged; the returned map
                  contains all the entries from <code>$week</code>, with one entry replaced by a
                  new entry. Both input maps contain an entry with the key <code>6</code>; the
                  one used in the result is the one that comes first in the input
                  sequence.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-merge-week">
               <fos:expression><eg>map:merge(
  ($week, { 6: "Sonnabend" }),
  { "duplicates": "combine" }
)</eg></fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: ("Samstag", "Sonnabend") }</eg></fos:result>
               <fos:postamble>The value of the existing map is unchanged; the returned map
                  contains all the entries from <code>$week</code>, with one entry replaced by a
                  new entry. Both input maps contain an entry with the key <code>6</code>; the
                  entry that appears in the result is the <xtermref spec="XP40" ref="dt-sequence-concatenation">sequence concatenation</xtermref> of the entries
                  in the input maps, retaining order.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:merge(
  ({ "oxygen": 0.22, "hydrogen": 0.68, "nitrogen": 0.1 },
   { "oxygen": 0.24, "hydrogen": 0.70, "nitrogen": 0.06 }), 
  { "duplicates": fn($a, $b) { max(($a, $b)) } })
               </eg></fos:expression>
               <fos:result>{ "oxygen": 0.24, "hydrogen": 0.70, "nitrogen": 0.1 }</fos:result>
               <fos:postamble>The result map holds, for each distinct key, the maximum of the values
               for that key in the input.</fos:postamble>
            </fos:test>
            

         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1725" PR="1727" date="2025-01-31">
            <p>For consistency with the new function <function>map:build</function>, the handling of duplicates
            may now be controlled by supplying a user-defined callback function as an alternative
            to the fixed values for the earlier <code>duplicates</code> option.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <!--<fos:function name="of-pairs" prefix="map">
      <fos:signatures>
         <fos:proto name="of-pairs" return-type="map(*)">
            <fos:arg name="input" 
                     type-ref="key-value-pair" type-ref-occurs="*"
                     usage="inspection"
                     example="{ 'key': 'n','value': false() }, { 'key': 'y','value': true() }"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a map that combines data from a sequence of 
            <termref def="dt-key-value-pair-map">key-value pair maps</termref>.</p>
      </fos:summary>
      <fos:rules>
         
         <p>The function <function>map:of-pairs</function>
            <phrase>returns a map</phrase> which
            is formed by combining <termref def="dt-key-value-pair-map">key-value pair maps</termref> supplied in the 
            <code>$input</code>
            argument.</p>
         
         <p>The <code>$options</code> argument can be used to control 
            the way in which duplicate keys are handled.
            The <termref def="option-parameter-conventions">option parameter conventions</termref> apply.
            
         </p>
 
         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>

         <fos:options>
  
            <fos:option key="duplicates">
               <fos:meaning>Determines the policy for handling duplicate keys: specifically, the action to be
                  taken if two entries in the input sequence have key values
                  <var>K1</var> and <var>K2</var> where <var>K1</var> and <var>K2</var> are the 
                  <termref
                     def="dt-same-key">same key</termref>. 
               </fos:meaning>
               <fos:type>(enum( "reject", "use-first", "use-last", "use-any", "combine") | fn(item()*, item()*) as item()*)?</fos:type>
               <fos:default>"combine"</fos:default>
               <fos:values>
                  <fos:value value='"reject"'>
                     Equivalent to supplying a function that raises a dynamic error
                     with error code "FOJS0003". The effect is that duplicate keys
                     result in an error.
                  </fos:value>
                  <fos:value value='"use-first"'
                        >Equivalent to supplying the function <code>fn($a, $b){ $a }</code>.
                     The effect is that the first of the duplicates is chosen.
                  </fos:value>
                  <fos:value value='"use-last"'
                        >Equivalent to supplying the function <code>fn($a, $b){ $b }</code>.
                     The effect is that the last of the duplicates is chosen.
                  </fos:value>
                  <fos:value value='"use-any"'
                        >Equivalent to supplying the function <code>fn($a, $b){ one-of($a, $b) }</code>
                     where <code>one-of</code> chooses either <code>$a</code> or <code>$b</code> in
                     an <termref def="implementation-dependent"/> way. The effect is that it is
                     <termref def="implementation-dependent"/> which of the duplicates is chosen.
                  </fos:value>
                  <fos:value value='"combine"'
                        >Equivalent to supplying the function <code>fn($a, $b){ $a, $b }</code>
                     (or equivalently, the function <code>op(",")</code>).
                     The effect is that the result contains the <xtermref spec="XP40" ref="dt-sequence-concatenation"/>
                     of the values having the same key, retaining order.
                  </fos:value>
                  <fos:value value="function(*)">
                     A function with signature <code>fn(item()*, item()*) as item()*</code>.
                     The function is called for any entry in the input sequence that has the 
                     <termref def="dt-same-key"/> as a previous entry. The first argument
                     is the existing value associated with the key; the second argument
                     is the value associated with the key in the duplicate input entry,
                     and the result is the new value to be associated with the key. The effect
                     is cumulative: for example if there are three values <var>X</var>, <var>Y</var>,
                     and <var>Z</var> associated with the same key, and the supplied function is
                     <var>F</var>, then the result is an entry whose value is 
                     <code><var>X</var> => <var>F</var>(<var>Y</var>) => <var>F</var>(<var>Z</var>)</code>.
                  </fos:value>
               </fos:values>
                        
             </fos:option>

         </fos:options>


               

      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false">
let $one-of := fn($a, $b) {
  (: select either $a or $b at implementation option :)
  if (environment-variable("X")) then $a else $b
}
let $duplicates := $options?duplicates
let $combine := if ($duplicates instance of xs:string) then (
  {
    "reject":    fn($a, $b) { error( #err:FOJS0003 ) },
    "use-first": fn($a, $b) { $a },
    "use-last":  fn($a, $b) { $b },
    "use-any":   fn($a, $b) { $one-of($a, $b) },
    "combine":   fn($a, $b) { $a, $b }
  }?$duplicates
) else if ($duplicates instance of fn(*)) then (
  $duplicates
) else (
  fn($a, $b) { $a, $b }
)
return fold-left(
  $input,
  {},
  fn($out, $next) {
    let $newVal := if (map:contains($out, $next?key)) then (
      $combine($out?($next?key), $next?value)
    ) else (
      $next?value
    )
    return map:put($result, $next?key, $newVal)
  }
)      </fos:equivalent>
      <fos:errors>
         
         <p>An error is raised <errorref spec="FO" class="JS" code="0003"
               /> if the value of 
          <code>$options</code> indicates that duplicates are to be rejected, and a duplicate key is encountered.</p>
         
         
      </fos:errors>

      <fos:notes>
         <p>In the formal equivalent shown above:</p>
         <ulist>
            <item><p>The call on <code>error()</code> is indicative; the implementation
            is free to raise the error in its own way.</p></item>
            <item><p>The function <code>$one-of($a, $b)</code> is intended to
            illustrate that either <code>$a</code> or <code>$b</code> is returned,
            at the discretion of the implementation. A function body is provided
            for completeness, but it is not intended as a realistic implementation.</p></item>
         </ulist>
         <p>If the input is the empty sequence, the result is the empty map.</p>
         <p>There is no requirement that the supplied key-value pairs should have the same or compatible
            types. The type of a map (for example <code>map(xs:integer, xs:string)</code>) is
            descriptive of the entries it currently contains, but is not a constraint on how the map
            may be combined with other maps.</p>
         <p>When duplicate keys are encountered, the effect is that:</p>
         <ulist>
            <item><p>In the <xtermref spec="DM40" ref="dt-entry-order"/> 
               of the result map, the position of the entry containing the result
               of combining a set of entries with duplicate keys corresponds to 
               the position of the first of the duplicates in the input sequence.</p></item>
            <item><p>The key of the combined entry 
                  will correspond to the key of one of the duplicates: it is
                  <termref def="implementation-dependent"/> which one is chosen.
               (Keys may be duplicates even though they differ: 
            for example they may have different type annotations, or they might be
            <code>xs:dateTime</code> values in different timezones.)</p></item>
         </ulist>
      </fos:notes>
      <fos:examples>
         <fos:variable name="week" id="v-map-of-week"
            select="{&#xa;  0: &quot;Sonntag&quot;, 1: &quot;Montag&quot;, 2: &quot;Dienstag&quot;, 3: &quot;Mittwoch&quot;,&#xa;  4: &quot;Donnerstag&quot;, 5: &quot;Freitag&quot;, 6: &quot;Samstag&quot;&#xa;}"/>
         <fos:example>
            <fos:test>
               <fos:expression>map:of-pairs(())</fos:expression>
               <fos:result>{}</fos:result>
               <fos:postamble>Returns the empty map</fos:postamble>
            </fos:test>
            <fos:test use="v-map-of-week">
               <fos:expression>map:of-pairs(map:pairs($week))</fos:expression>
               <fos:result><eg>{
  0: &quot;Sonntag&quot;,
  1: &quot;Montag&quot;, 
  2: &quot;Dienstag&quot;,
  3: &quot;Mittwoch&quot;, 
  4: &quot;Donnerstag&quot;,
  5: &quot;Freitag&quot;, 
  6: &quot;Samstag&quot;
}</eg></fos:result>
               <fos:postamble>The function <function>map:of-pairs</function> is the inverse of
                  <function>map:pairs</function>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[map:of-pairs((
  { "key": 0, "value": "no" },
  { "key": 1, "value": "yes" }
))]]></eg></fos:expression>
               <fos:result>{ 0: "no", 1: "yes" }</fos:result>
               <fos:postamble>Returns a map with two entries</fos:postamble>
            </fos:test>
            <fos:test use="v-map-of-week">
               <fos:expression><eg>map:of-pairs((
  map:pairs($week),
  { "key": 7, "value": "Unbekannt" }
))</eg></fos:expression>
               <fos:result>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag", 7: "Unbekannt" }</fos:result>
               <fos:postamble>The value of the existing map is unchanged; the returned map 
                  contains all the entries from <code>$week</code>, supplemented 
                  with an additional entry.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-of-week">
               <fos:expression><eg>map:of-pairs((
  map:pairs($week),
  { "key": 6, "value": "Sonnabend" }
))</eg></fos:expression>
               <fos:result>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: ("Samstag", "Sonnabend") }</fos:result>
               <fos:postamble>The value of the existing map is unchanged; the returned map
                  contains all the entries from <code>$week</code>, with one entry replaced by a
                  new entry. Both input maps contain an entry with the key <code>6</code>; the
                  one used in the result combines the two supplied values into a single sequence.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-of-week">
               <fos:expression><eg>map:of-pairs(
  (map:pairs($week), { "key": 6, "value": "Sonnabend" }),
  { "duplicates": "use-last" }
)</eg></fos:expression>
               <fos:result>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Sonnabend" }</fos:result>
               <fos:postamble>The value of the existing map is unchanged; the returned map
                  contains all the entries from <code>$week</code>, with one entry replaced by a
                  new entry. Both input maps contain an entry with the key <code>6</code>; the
                  supplied <code>$duplicates</code> option ensures that the one used in the result 
                  is the one that comes last in the input sequence.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-of-week">
               <fos:expression><eg>map:of-pairs(
  (map:pairs($week), { "key": 6, "value": "Sonnabend" }),
  { "duplicates": concat(?, '|', ?) }
)</eg></fos:expression>
               <fos:result>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag|Sonnabend" }</fos:result>
               <fos:postamble>In the result map, the value for key <code>6</code> is obtained by concatenating the values
                  from the two input maps, with a separator character.</fos:postamble>
            </fos:test>
            
            <fos:test>
               <fos:expression><eg>map:of-pairs(
  (
    map:pairs({ "England": 2, "Germany": 1 }),
    map:pairs({ "France": 2, "Germany": 2 }),
    map:pairs({ "England": 0, "France": 1 })
  ),
  { "duplicates": op("+") }
)</eg></fos:expression>
            
            <fos:result>{ "England": 2, "Germany": 3, "France": 3 }</fos:result>
               <fos:postamble>The values for each distinct key are summed.</fos:postamble>
            </fos:test>
            
            <fos:test>
               <fos:expression><eg>map:of-pairs(
  (map:pair("red", 0), map:pair("green", 1), map:pair("blue", 2))
)
=> map:keys()</eg></fos:expression>
               <fos:result>"red", "green", "blue"</fos:result>
               <fos:postamble>The keys are returned in the order supplied.</fos:postamble>
            </fos:test>
            
            <fos:test>
               <fos:expression><eg>{ "red": 0, "green": 1, "blue": 2 }
=> map:pairs()
=> sort(key := fn { ?key })
=> map:of-pairs()
=> map:keys()</eg></fos:expression>
               <fos:result>"blue", "green", "red"</fos:result>
               <fos:postamble>Takes any map and produces a map with the same entries, but sorted by key.</fos:postamble>
            </fos:test>
            
            <fos:test>
               <fos:expression><eg>map:of-pairs(
  (map:pair("red", 0), map:pair("green", 1), map:pair("blue", 2))
)
=> map:put("yellow", -1)
=> map:keys()</eg></fos:expression>
               <fos:result>"red", "green", "blue", "yellow"</fos:result>
               <fos:postamble>New entries are added at the end.</fos:postamble>
            </fos:test>

         </fos:example>
         
         <fos:example>
            <p>The following expression takes an existing map and sorts its entries into key order:</p>
            <eg>map:of-pairs(map:pairs($M) => sort(key := fn { ?key }))</eg>
            
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>-->

   <fos:function name="keys" prefix="map">
      <fos:signatures>
         <fos:proto name="keys" return-type="xs:anyAtomicType*">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence containing all the keys present in a map.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function <function>map:keys</function> takes any
            <termref def="dt-map">map</termref> as its <code>$map</code> argument and returns
            the keys that are present in the map as a sequence of atomic items, 
            in <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref>.</p>
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:for-each($map, fn($key, $value) { $key })
      </fos:equivalent>
      <fos:notes>
         <p>The number of items in the result will be the same as the number of entries in the map,
            and the result sequence will contain no duplicate values.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>map:keys({ 1: "yes", 0: "no" })</fos:expression>
               <fos:result>(1, 0)</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>({ "red": 0}, { "blue": 1}, { "green": 2 })
=> map:merge()
=> map:keys()</eg></fos:expression>
               <fos:result>("red", "blue", "green")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="keys-where" prefix="map">
      <fos:signatures>
         <fos:proto name="keys-where" return-type="xs:anyAtomicType*">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="predicate" type="fn($key as xs:anyAtomicType, $value as item()*) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence containing selected keys present in a map.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function <function>map:keys</function> takes any
            <termref def="dt-map">map</termref> as its <code>$map</code> argument. The
            <code>$predicate</code> function takes the key and the value of the corresponding
            map entry as an argument, and the result is a sequence containing the keys of those
            entries for which the predicate function returns <code>true</code>, in 
            <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref>.</p>
         
         <p>A return value of <code>()</code> from the predicate function is 
            treated as <code>false</code>.</p>
         
         <!--<p>The function is <term>nondeterministic with respect to ordering</term>
            (see <specref
               ref="properties-of-functions"
            />). This means that two calls with the same argument
            are not guaranteed to produce the results in the same order.</p>-->
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:for-each($map, fn($key, $value) {
  if ($predicate($key, $value)) { $key }
})         
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
let $numbers := {
  0: "zero",
  1: "one",
  2: "two",
  3: "three"
}
return map:keys-where(
  $numbers,
  fn($key, $value) { $value = ("two", "three") }
)
               </eg></fos:expression>
               <fos:result>(2, 3)</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
let $square := map:merge(
  (1 to 5) ! map:entry(., . * .)
)
return map:keys-where(
  $square,
  fn($key, $value) { $value &gt; 5 and $value &lt; 20 }
)
               </eg></fos:expression>
               <fos:result>(3, 4)</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
let $birthdays := {
  "Agnieszka": xs:date("1980-12-31"),
  "Jabulile": xs:date("2001-05-05"),
  "Joel": xs:date("1969-11-10"),
  "Midori": xs:date("2012-01-08")
}
return map:keys-where($birthdays, fn($name, $date) {
  starts-with($name, "J") and year-from-date($date) = 1969
})
               </eg></fos:expression>
               <fos:result>"Joel"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="467 504" PR="478 515" date="2023-05-16"><p>New in 4.0</p></fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="items" prefix="map">
      <fos:signatures>
         <fos:proto name="items" return-type="item()*">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence containing all the values present in a map, in order.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:items</function> takes any <termref def="dt-map"
            >map</termref>
            as its <code>$map</code> argument and returns the values that are present in the map as
            a sequence, in <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref>.</p>
         
         <p>The effect of the function is equivalent to <code>$map?*</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:for-each($map, fn($key, $value) { $value })
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:items({ 1: "yes", 2: "no" })</eg></fos:expression>
               <fos:result>("yes", "no")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:items({
  1: ("red", "green"),
  2: ("blue", "yellow"),
  3: ()
})</eg></fos:expression>
               <fos:result>("red", "green", "blue", "yellow")</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1672" PR="1687" date="2025-01-14"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="entries" prefix="map">
      <fos:signatures>
         <fos:proto name="entries" return-type="map(*)*">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence containing all the key-value pairs present in a map, each represented
            as a <termref def="dt-single-entry-map"/>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:entries</function> takes any <termref def="dt-map"
            >map</termref>
            as its <code>$map</code> argument and returns the key-value pairs that are present in the map as
            a sequence of <termref def="dt-single-entry-map">single-entry maps</termref>, in 
            <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref>.</p>
         
         

      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:for-each($map, map:entry#2)
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:entries(
  { 1: "yes", 0: "no" }
)</eg></fos:expression>
               <fos:result>({ 1: "yes" }, { 0: "no" })</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="29 314" PR="360" date="2023-03-21"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <!--<fos:function name="pairs" prefix="map">
      <fos:signatures>
         <fos:proto name="pairs" return-type-ref="key-value-pair" return-type-ref-occurs="*">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence containing all the key-value pairs present in a map, each represented
         as a <termref def="dt-key-value-pair-map"/>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:pairs</function> takes any <termref def="dt-map"
            >map</termref>
            as its <code>$map</code> argument and returns the keys that are present in the map as
            a sequence of <termref def="dt-key-value-pair-map">key-value pair maps</termref>, in 
            <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref>.</p>
         <p>A key-value pair map is an instance of type <code>record(key as xs:anyAtomicType, value as item()*)</code>:
         that is a map with two entries, one (with key <code>"key"</code>) holding the key,
         and the other (with key <code>"value"</code>) holding the value.</p>
         
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:for-each($map, map:pair#2)
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:pairs({ 1: "Y", 2: "N" })</eg></fos:expression>
               <fos:result><eg>({ "key": 1, "value": "Y" }, { "key": 2, "value": "N" })</eg></fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <any-of>
                        <assert-deep-eq>{ "key": 1, "value": "Y" }, { "key": 2, "value": "N" }</assert-deep-eq>
                        <assert-deep-eq>{ "key": 2, "value": "N" }, { "key": 1, "value": "Y" }</assert-deep-eq>
                     </any-of>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>-->
   
   <!--<fos:function name="ordered" prefix="map">
      <fos:signatures>
         <fos:proto name="ordered" return-type="xs:boolean">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <code>ordered</code> property of a map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the value of the 
            <xtermref spec="DM40" ref="dt-map-ordered"/> property of a map.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:ordered({ 1: "Y", 2: "N" })</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>

         <fos:example>
            <fos:test>
               <fos:expression><eg>map:ordered(
   map:merge(({ 1: "Y" }, { 2: "N" }), 
   { "retain-order" : true() })
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>-->

   <fos:function name="contains" prefix="map">
      <fos:signatures>
         <fos:proto name="contains" return-type="xs:boolean">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="key" type="xs:anyAtomicType"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Tests whether a supplied map contains an entry for a given key.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:contains</function> returns <code>true</code> if the <termref def="dt-map"
               >map</termref> supplied as <code>$map</code> contains an entry with the <termref
                  def="dt-same-key">same key</termref> as <code>$key</code>; otherwise it returns <code>false</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
some(map:keys($map), atomic-equal(?, $key))
      </fos:equivalent>
      <fos:examples>
         <fos:variable name="week" id="v-map-contains-week"
            select="{&#xa;  0: &quot;Sonntag&quot;, 1: &quot;Montag&quot;, 2: &quot;Dienstag&quot;, 3: &quot;Mittwoch&quot;,&#xa;  4: &quot;Donnerstag&quot;, 5: &quot;Freitag&quot;, 6: &quot;Samstag&quot;&#xa;}"/>
         <fos:example>
            <fos:test use="v-map-contains-week">
               <fos:expression>map:contains($week, 2)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test use="v-map-contains-week">
               <fos:expression>map:contains($week, 9)</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>map:contains({}, "xyz")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>map:contains({ "xyz": 23 }, "xyz")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>map:contains({ "abc": 23, "xyz": () }, "xyz")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="empty" prefix="map">
      <fos:signatures>
         <fos:proto name="empty" return-type="xs:boolean">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the supplied map contains no entries.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>true</code> if and only if <code>$map</code> contains no
            entries, that is, if <code>map:size($map) eq 0</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:size($map) eq 0
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>map:empty({})</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>map:empty({ 1: () })</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="827 843" PR="969" date="2023-11-18"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="get" prefix="map">
      <fos:signatures>
         <fos:proto name="get" return-type="item()*">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="key" type="xs:anyAtomicType"/>
            <fos:arg name="default" type="item()*" default="()" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value associated with a supplied key in a given map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:get</function> attempts to find an entry within the <termref
               def="dt-map"
               >map</termref> supplied as <code>$map</code> that has 
            the <termref
               def="dt-same-key"
               >same key</termref> as <code>$key</code>. If there is such an entry, it returns the associated value;
            if not, it returns the supplied <code>$default</code> value.</p>

      </fos:rules>
      <fos:equivalent style="dm-primitive">
let $entry := dm:iterate-map($map, fn($k, $v) {
  if (atomic-equal($k, $key)) {
    map:entry($k, $v)
  }
})
return (
  if (exists($entry))
  then map:items($entry)
  else $default
)
      </fos:equivalent>
      <fos:notes>
         <p>A return value of <code>()</code> from <function>map:get#2</function> could indicate that
            the key is present in the map with an associated value of <code>()</code>, or it could
            indicate that the key is not present in the map. The two cases can be distinguished by
            either by calling <function>map:contains</function> to test whether an entry is present, or by using
            a <code>$default</code> value to return a value known never to appear in the map.</p>
         


         <p>Invoking the <termref def="dt-map"
               >map</termref> as a function item has the same effect
            as calling <code>get</code> with no <code>$default</code>
            argument: that is, when <code>$map</code> is a map, the expression
               <code>$map($K)</code> is equivalent to <code>map:get($map, $K)</code>. Similarly, the
            expression <code>map:get(map:get(map:get($map, 'employee'), 'name'), 'first')</code> can
            be written as <code>$map('employee')('name')('first')</code>.</p>

      </fos:notes>
      <fos:examples>
         <fos:variable name="week" id="v-map-get-week"
            select="{&#xa;  0: &quot;Sonntag&quot;, 1: &quot;Montag&quot;, 2: &quot;Dienstag&quot;, 3: &quot;Mittwoch&quot;,&#xa;  4: &quot;Donnerstag&quot;, 5: &quot;Freitag&quot;, 6: &quot;Samstag&quot;&#xa;}"/>
         <fos:example>
            <fos:test use="v-map-get-week">
               <fos:expression>map:get($week, 4)</fos:expression>
               <fos:result>"Donnerstag"</fos:result>
            </fos:test>
            <fos:test use="v-map-get-week">
               <fos:expression>map:get($week, 9)</fos:expression>
               <fos:result>()</fos:result>
               <fos:postamble>When the key is not present, the function returns the empty
                  sequence.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>map:get(map:entry(7,()), 7)</fos:expression>
               <fos:result>()</fos:result>
               <fos:postamble>An empty sequence as the result can also signify that the key is
                  present and the associated value is the empty sequence.</fos:postamble>
            </fos:test>
            <fos:test use="v-map-get-week">
               <fos:expression>map:get($week, 7, "n/a")</fos:expression>
               <fos:result>"n/a"</fos:result>
               <fos:postamble>The third argument supplies a default value.</fos:postamble>
            </fos:test>
            <!--<fos:test>
               <fos:expression><eg>{ 1: "single", 2: "double", 3: "triple" }
=> map:get(10, fn { . || "-fold" })</eg></fos:expression>
               <fos:result>"10-fold"</fos:result>
               <fos:postamble>The map holds special cases; the fallback function handles other cases.</fos:postamble>
            </fos:test>-->
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1363" PR="289 1901" date="2025-04-15"><p>A third argument is added, allowing user control of how absent keys should be handled.</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="find" prefix="map">
      <fos:signatures>
         <fos:proto name="find" return-type="array(*)">
            <fos:arg name="input" type="item()*" usage="inspection"/>
            <fos:arg name="key" type="xs:anyAtomicType"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Searches the supplied input sequence and any contained maps and arrays for a map entry with the supplied key,
            and returns the corresponding values.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:find</function> searches the sequence supplied as <code>$input</code>
         looking for map entries whose key is the <termref
               def="dt-same-key"
            >same key</termref>
         as <code>$key</code>. The associated value in any such map entry (each being in general a sequence)
         is returned as a member of the result array.</p>

         <p>The search processes the <code>$input</code> sequence using the following recursively defined rules 
            (any equivalent algorithm may be used provided it delivers
            the same result, respecting those rules that constrain the order of the result):</p>

         <olist>
            <item>
               <p>To process a sequence, process each of its items in order.</p>
            </item>
            <item>
               <p>To process an item that is an array, process each of its members in order 
               (each member is, in general, a sequence).</p>
            </item>
            <item>
               <p>To process an item that is a map, then for each key-value entry (<var>K</var>, <var>V</var>)
               in the map (in <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref>)
               perform both of the following steps, in order:</p>
               <olist>
                  <item>
                     <p>If <var>K</var> is the <termref def="dt-same-key"
                           >same key</termref> as <code>$key</code>, 
                  then add <var>V</var> as a new member to the end of the result array.</p>
                  </item>
                  <item>
                     <p>Process <var>V</var> (which is, in general, a sequence).</p>
                  </item>
               </olist>
            </item>
            <item>
               <p>To process an item that is neither a map nor an array, do nothing. (Such items are ignored).</p>
            </item>
         </olist>

      </fos:rules>
      <!--<fos:equivalent style="xquery-function">
declare function map:find(
  $input as item()*, 
  $key as xs:anyAtomicType
) as array(*) {
  array:of-members(                       
    for $item in $input
    return typeswitch ($item) {
      case $a as array(*) return
        for member $member in $a
        return map:find($member, $key)
      case $m as map(*) return
        for key $k value $v in $m
        return (
          if (atomic-equal($k, $key)) { { 'value': $v } },
          map:find($v, $key)
        )
      default return ()
    }
  )
};   
      </fos:equivalent>-->
      <fos:notes>
         <p>If <code>$input</code> is the empty sequence, map, or array, or if the requested <code>$key</code> is not found,
            the result will be a zero-length array.</p>

      </fos:notes>
      <fos:examples>
         <fos:variable name="responses" id="v-map-find-responses"
            select="[&#xa;  { 0: 'no', 1: 'yes' },&#xa;  { 0: 'non', 1: 'oui' },&#xa;  { 0: 'nein', 1: ('ja', 'doch') }&#xa;]"/>
         <fos:example>
            <fos:test use="v-map-find-responses">
               <fos:expression>map:find($responses, 0)</fos:expression>
               <fos:result>[ 'no', 'non', 'nein' ]</fos:result>
            </fos:test>
            <fos:test use="v-map-find-responses">
               <fos:expression>map:find($responses, 1)</fos:expression>
               <fos:result>[ 'yes', 'oui', ('ja', 'doch') ]</fos:result>
            </fos:test>
            <fos:test use="v-map-find-responses">
               <fos:expression>map:find($responses, 2)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>

         </fos:example>
         <fos:variable name="inventory" id="v-map-find-inventory"
            select='{&#xa;  "name": "car",&#xa;  "id": "QZ123", &#xa;  "parts": [ { "name": "engine", "id": "YW678", "parts": [] } ]&#xa;}'/>
         <fos:example>
            <fos:test use="v-map-find-inventory">
               <fos:expression>map:find($inventory, "parts")</fos:expression>
               <fos:result><eg>[
  [ { "name": "engine", "id": "YW678", "parts": [] } ],
  []
]</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change  issue="1651" PR="1703" date="2025-01-14"><p>Enhanced to allow for ordered maps.</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="put" prefix="map">
      <fos:signatures>
         <fos:proto name="put" return-type="map(*)">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="key" type="xs:anyAtomicType"/>
            <fos:arg name="value" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a map containing all the contents of the supplied map, but with an additional entry, which replaces
         any existing entry for the same key.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$map</code> contains an entry whose key is the <termref
               def="dt-same-key">same key</termref> as <code>$key</code>, the function returns
         a map in which that entry is replaced (at the same relative position)
         with a new entry whose value is <code>$value</code>. It is 
         <termref def="implementation-dependent"/> whether the key in the new entry
         takes its original value or is replaced by the supplied <code>$key</code>.
         All other entries in the map are unchanged, and retain their relative order.</p>
         
         <p>Otherwise, when <code>$map</code> contains no such entry, the function
         returns a map containing all entries from the supplied <code>$map</code>
         (retaining their relative position) followed by a new entry whose key
         is <code>$key</code> and whose associated value is <code>$value</code>.</p>

      </fos:rules>
      
      <fos:equivalent style="dm-primitive">
          dm:map-put($map, $key, $value)
      </fos:equivalent>
      


      <fos:notes>
         <p>There is no requirement that the type of <code>$key</code> and <code>$value</code> be consistent with the types
         of any existing keys and values in the supplied map.</p>
         
         <p>It is possible to force the new entry to go at the end of the sequence by calling
         <code>map:remove</code> before calling <code>map:put</code>.</p>
         
         <p>It can happen that the supplied <code>$key</code> is the <termref def="dt-same-key"/>
            as some existing key present in <code>$map</code>, but nevertheless 
            differs from the existing key in some way:
         for example, it might have a different type annotation, or it might be an <code>xs:dateTime</code>
         value in a different timezone. In this situation it is 
         <termref def="implementation-dependent"/> whether the key that appears in the result map
         is the supplied <code>$key</code> or the existing key.</p>

      </fos:notes>

      <fos:examples>
         <fos:variable name="week" id="v-map-put-week"
            select="{&#xa;  0: &quot;Sonntag&quot;, 1: &quot;Montag&quot;, 2: &quot;Dienstag&quot;, 3: &quot;Mittwoch&quot;,&#xa;  4: &quot;Donnerstag&quot;, 5: &quot;Freitag&quot;, 6: &quot;Samstag&quot;&#xa;}"/>
         <fos:example>
            <fos:test use="v-map-put-week">
               <fos:expression>map:put($week, 6, "Sonnabend")</fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Sonnabend" }</eg></fos:result>
            </fos:test>
            <fos:test use="v-map-put-week">
               <fos:expression>map:put($week, -1, "Unbekannt")</fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag", -1: "Unbekannt" }</eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json('{ "red": 0, "green": 1, "blue": 2 }')
=> map:put("yellow", -1) 
=> map:keys()</eg></fos:expression>
               <fos:result>"red", "green", "blue", "yellow"</fos:result>
               <fos:postamble>The new entry is added at the end of the list.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json('{ "red": 0, "green": 1, "blue": 2 }')
=> map:put("red", -1) 
=> map:keys()</eg></fos:expression>
               <fos:result>"red", "green", "blue"</fos:result>
               <fos:postamble>Changing the value for an existing key does not 
                  change the order of the keys.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1651" PR="1703" date="2025-01-14">
            <p>Enhanced to allow for ordered maps.</p>
         </fos:change>
         <fos:change issue="1725" PR="1727 1740" date="2025-01-28">
            <p>It is no longer guaranteed that the new key replaces the existing key.</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="entry" prefix="map">
      <fos:signatures>
         <fos:proto name="entry" return-type="map(*)">
            <fos:arg name="key" type="xs:anyAtomicType"/>
            <fos:arg name="value" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p><phrase>Returns</phrase> a <termref def="dt-single-entry-map"/> that 
            represents a single key-value pair.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:entry</function> returns a <termref def="dt-map"
               >map</termref> which  contains a single
            entry. The key of the entry in the new map is
               <code>$key</code>, and its associated value is <code>$value</code>.</p>



      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:put({}, $key, $value)
      </fos:equivalent>
      <fos:notes>
         
         <p>The function <function>map:entry</function> is intended primarily for use in conjunction with
            the function <function>map:merge</function>. For example, a map containing seven entries may be
            constructed like this:</p>

         <eg><![CDATA[
map:merge((
  map:entry("Su", "Sunday"),
  map:entry("Mo", "Monday"),
  map:entry("Tu", "Tuesday"),
  map:entry("We", "Wednesday"),
  map:entry("Th", "Thursday"),
  map:entry("Fr", "Friday"),
  map:entry("Sa", "Saturday")
))]]></eg>
         <p>The <function>map:merge</function> function can be used to construct
            a map with a variable number of entries, for example:</p>
         <eg><![CDATA[
map:merge(//book ! map:entry(isbn, .))]]></eg>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>map:entry("M", "Monday")</fos:expression>
               <fos:result>{ "M": "Monday" }</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <!--<fos:function name="pair" prefix="map">
      <fos:signatures>
         <fos:proto name="pair" return-type-ref="key-value-pair">
            <fos:arg name="key" type="xs:anyAtomicType"/>
            <fos:arg name="value" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p><phrase>Returns</phrase> a <termref def="dt-key-value-pair-map"/> that 
            represents a single key-value pair.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:pair</function> returns a <termref def="dt-map"
            >map</termref> which contains two entries, one (with the key <code>"key"</code>)
            containing <code>$key</code> and the other (with the key <code>"value"</code>)
            containing <code>$value</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
{}
=> map:put("key", $key)
=> map:put("value", $value)
      </fos:equivalent>
      <fos:notes>
         <p>The function call <code>map:pair(K, V)</code> produces the same result as the
         expression <code>{ "key": K, "value": V }</code>.</p>
         <p>The function <function>map:pair</function> is intended primarily for use in conjunction with
            the function <function>map:of-pairs</function>. A map may be constructed like this:</p>

         <eg><![CDATA[
map:of-pairs((
  map:pair("Su", "Sunday"),
  map:pair("Mo", "Monday"),
  map:pair("Tu", "Tuesday"),
  map:pair("We", "Wednesday"),
  map:pair("Th", "Thursday"),
  map:pair("Fr", "Friday"),
  map:pair("Sa", "Saturday")
))]]></eg>
         <p>The <function>map:of-pairs</function> function can be used to construct
            a map with a variable number of entries, for example:</p>
         <eg><![CDATA[map:of-pairs(//book ! map:pair(./isbn, .))]]></eg>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>map:pair("M", "Monday")</fos:expression>
               <fos:result>{ "key": "M", "value": "Monday" }</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>-->

   <fos:function name="remove" prefix="map">
      <fos:signatures>
         <fos:proto name="remove" return-type="map(*)">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="keys" type="xs:anyAtomicType*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a map containing all the entries from a supplied map, except <phrase>those having a specified key</phrase>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:remove</function> returns a <termref def="dt-map"
               >map</termref> containing all the entries in <code>$map</code> except for any entry whose key is 
            the <termref
               def="dt-same-key">same key</termref> as <phrase>an item in</phrase>
            <code>$keys</code>.</p>
         <p>No failure occurs <phrase>if an item in <code>$keys</code> does not correspond to any entry in <code>$map</code>;
            that key value is simply ignored</phrase>.</p>
         <p>The relative position of retained entries in the result map 
            is the same as their relative position in <code>$map</code>.</p>
        
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:filter(
  $map,
  fn($k, $v) { not(some($keys, atomic-equal($k, ?))) }
)
      </fos:equivalent>

      <fos:examples>
         <fos:variable name="week" id="v-map-remove-week"
            select="{&#xa;  0: &quot;Sonntag&quot;, 1: &quot;Montag&quot;, 2: &quot;Dienstag&quot;, 3: &quot;Mittwoch&quot;,&#xa;  4: &quot;Donnerstag&quot;, 5: &quot;Freitag&quot;, 6: &quot;Samstag&quot;&#xa;}"/>
         <fos:example>
            <fos:test use="v-map-remove-week">
               <fos:expression>map:remove($week, 4)</fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  5: "Freitag", 6: "Samstag" }</eg></fos:result>
            </fos:test>
            <fos:test use="v-map-remove-week">
               <fos:expression>map:remove($week, 23)</fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag" }</eg></fos:result>
            </fos:test>
            <fos:test use="v-map-remove-week">
               <fos:expression>map:remove($week, (0, 6 to 7))</fos:expression>
               <fos:result><eg>{ 1: "Montag", 2: "Dienstag", 3: "Mittwoch", 4: "Donnerstag",
  5: "Freitag" }</eg></fos:result>
            </fos:test>
            <fos:test use="v-map-remove-week">
               <fos:expression>map:remove($week, ())</fos:expression>
               <fos:result><eg>{ 0: "Sonntag", 1: "Montag", 2: "Dienstag", 3: "Mittwoch",
  4: "Donnerstag", 5: "Freitag", 6: "Samstag" }</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change  issue="1651" PR="1703" date="2025-01-14"><p>Enhanced to allow for ordered maps.</p></fos:change>
      </fos:changes>
   </fos:function>
   <fos:function name="for-each" prefix="map">
      <fos:signatures>
         <fos:proto name="for-each" return-type="item()*">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="action" type="fn($key as xs:anyAtomicType, $value as item()*, $position as xs:integer) as item()*"
               usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Applies a supplied function to every entry in a map, returning the 
            <xtermref spec="XP40" ref="dt-sequence-concatenation">sequence concatenation</xtermref> of the results.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:for-each</function> takes any <termref def="dt-map"
               >map</termref> as its <code>$map</code> argument and applies the supplied function
            to each entry in the map, in <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref>; 
            the result is the <xtermref spec="XP40" ref="dt-sequence-concatenation"/> 
            of the results of these function calls.</p>
         
         <p>The function supplied as <code>$action</code> takes three arguments. It is called
            supplying the key of the map entry as the first argument, the associated value as
            the second argument, and the 1-based integer position as the third argument.</p>
      </fos:rules>
      
      <fos:equivalent style="dm-primitive">
        dm:iterate-map($map, $action, $position)
      </fos:equivalent>

      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:for-each(
  { 1: "yes", 2: "no" },
  fn($k, $v) { $k }
)</eg></fos:expression>
               <fos:result>(1, 2)</fos:result>
               <fos:postamble>This function call is equivalent to calling <code>map:keys</code>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>distinct-values(
  map:for-each(
    { 1: "yes", 2: "no" },
    fn($k, $v) { $v }
  )
)</eg></fos:expression>
               <fos:result>("yes", "no")</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:merge(
  map:for-each(
    { "a": 1, "b": 2 },
    fn($k, $v) { map:entry($k, $v + 1) }
  )
)</eg></fos:expression>
               <fos:result>{ "a": 2, "b": 3 }</fos:result>
               <fos:postamble>This function call returns a map with the same keys as the input map,
                  with the value of each entry increased by one.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>

            <p>This XQuery example converts the entries in a map to attributes on a newly constructed
                  element node:</p>

            <eg><![CDATA[
let $dimensions := { 'height': 3, 'width': 4, 'depth': 5 }
return <box>{
  map:for-each($dimensions, fn($k, $v) { attribute { $k } { $v } })
}</box>]]></eg>

            <p>The result is the element <code>&lt;box height="3" width="4"
                  depth="5"/></code>.</p>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
let $en-ja := { 'one': '一', 'two': '二', 'three': '三' }
return map:for-each($en-ja, fn($en, $ja, $pos) {
  $pos || '. ' || $en || ': ' || $ja
})]]></eg></fos:expression>
               <fos:result>"1. one: 一", "2. two: 二", "3. three: 三"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change  issue="1651" PR="1703" date="2025-01-14"><p>Enhanced to allow for ordered maps.</p></fos:change>
         <fos:change  issue="1718" PR="2224" date="2025-10-02">
            <p>The <code>$action</code> callback function now accepts an optional position argument.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="filter" prefix="map">
      <fos:signatures>
         <fos:proto name="filter" return-type="map(*)">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="predicate" type="fn($key as xs:anyAtomicType, $value as item()*, $position as xs:integer) as xs:boolean?"
               usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>        
      </fos:properties>
      <fos:summary>
         <p>Selects entries from a map, returning a new map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:filter</function> takes any <termref def="dt-map"
               >map</termref> as its <code>$map</code> argument and applies the supplied function
            to each entry in the map; the result is a new map containing those entries for which
            the function returns <code>true</code>. A return value of <code>()</code> from the
         predicate is treated as <code>false</code>.</p>

         <p>The function supplied as <code>$predicate</code> takes three arguments. It is called
            supplying the key of the map entry as the first argument, the associated value as
            the second argument, and the 1-based integer position as the third argument.</p>
         
         <p>The relative <xtermref spec="DM40" ref="dt-entry-order">order of entries</xtermref> 
            in the returned map is the same as their relative order in <code>$map</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:for-each($map, fn($key, $value, $position) {
  if ($predicate($key, $value, $position)) {
    map:entry($key, $value)
  }
})
=> map:merge()                   
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:filter(
  { 1: "Sunday", 2: "Monday", 3: "Tuesday", 4: "Wednesday",
    5: "Thursday", 6: "Friday", 7: "Saturday" },
  fn($k, $v) { $k = (1, 7) }
)</eg></fos:expression>
               <fos:result><eg>{ 1: "Sunday", 7: "Saturday" }</eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:filter(
  { 1: "Sunday", 2: "Monday", 3: "Tuesday", 4: "Wednesday",
    5: "Thursday", 6: "Friday", 7: "Saturday" },
  fn($k, $v) { $v = ("Saturday", "Sunday") }
)</eg></fos:expression>
               <fos:result><eg>{ 1: "Sunday", 7: "Saturday" }</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
let $en-ja := { 'one': '一', 'two': '二', 'three': '三' }
return map:filter($en-ja, fn($en, $ja, $pos) {
  $pos mod 2 = 1
})]]></eg></fos:expression>
               <fos:result>{ 'one': '一', 'three': '三' }</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="584 843 1074 1133" PR="969 1134" date="2023-07-11"><p>New in 4.0</p></fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
         <fos:change  issue="1651" PR="1703" date="2025-01-14"><p>Enhanced to allow for ordered maps.</p></fos:change>
         <fos:change  issue="1718" PR="2224" date="2025-10-02">
            <p>The <code>$action</code> callback function now accepts an optional position argument.</p>
         </fos:change>
      </fos:changes>
   </fos:function>


   <fos:function name="build" prefix="map">
      <fos:signatures>
         <fos:proto name="build" return-type="map(*)">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="key" type="(fn($item as item(), $position as xs:integer) as xs:anyAtomicType*)?" default="fn:identity#1" usage="inspection" note="default-on-empty"/>
            <fos:arg name="value" type="(fn($item as item(), $position as xs:integer) as item()*)?" default="fn:identity#1" usage="inspection" note="default-on-empty"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns a map that typically contains one entry for each item in a supplied input sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function processes each item in <code>$input</code> in order.
            It calls the <code>$key</code> function on that item to obtain a sequence of key values,
            and the <code>$value</code> function to obtain an associated value.
            Then, for each key value:</p>
         <ulist>
            <item><p>If the key is not already present in the target map, the processor adds a
               new key-value pair to the map, with that key and that value. </p></item>
            <item><p>If the key is already present, the processor combines the new value for the key
               with the existing value; the way they are combined is determined by the 
               <code>duplicates</code> option.</p>
               <p>By default, when two duplicate entries occur:</p>
               <ulist>
                  <item><p>A single combined entry will be present in the result.</p></item>
                  <item><p>This entry will contain the 
                     <xtermref spec="XP40" ref="dt-sequence-concatenation">sequence concatenation</xtermref>
                  of the supplied values.</p></item>
                  <item><p>The position of the combined entry in the
                  <xtermref spec="DM40" ref="dt-entry-order"/> of the result map
                  will correspond to the position of the first of the duplicates.</p></item>
                  <item><p>The key of the combined entry 
                  will correspond to the key of one of the duplicates: it is
                  <termref def="implementation-dependent"/> which one is chosen.
                  (It is possible for two keys to be considered duplicates even if they differ:
                  for example, they may have different type annotations, or they may
                  be <code>xs:dateTime</code> values in different timezones.) </p></item>
               </ulist>
               <p>The <code>$options</code> argument can be used to control the 
            way in which duplicate keys are handled. 
            The <termref def="option-parameter-conventions">option parameter conventions</termref> apply.
            The entries that may appear in the <code>$options</code> map are as follows:</p>

         <fos:options>
  
            <fos:option key="duplicates">
               <fos:meaning>Determines the policy for handling duplicate keys: specifically, the action to be
                  taken if two entries in the input sequence have key values
                  <var>K1</var> and <var>K2</var> where <var>K1</var> and <var>K2</var> are the 
                  <termref
                     def="dt-same-key">same key</termref>. 
               </fos:meaning>
               <fos:type>(enum( "reject", "use-first", "use-last", "use-any", "combine") | fn(item()*, item()*) as item()*)?</fos:type>
               <fos:default>"combine"</fos:default>
               <fos:values>
                  <fos:value value='"reject"'>
                     Equivalent to supplying a function that raises a dynamic error
                     with error code "FOJS0003". The effect is that duplicate keys
                     result in an error.
                  </fos:value>
                  <fos:value value='"use-first"'
                        >Equivalent to supplying the function <code>fn($a, $b){ $a }</code>.
                     The effect is that the first of the duplicates is chosen.
                  </fos:value>
                  <fos:value value='"use-last"'
                        >Equivalent to supplying the function <code>fn($a, $b){ $b }</code>.
                     The effect is that the last of the duplicates is chosen.
                  </fos:value>
                  <fos:value value='"use-any"'
                        >Equivalent to supplying the function <code>fn($a, $b){ one-of($a, $b) }</code>
                     where <code>one-of</code> chooses either <code>$a</code> or <code>$b</code> in
                     an <termref def="implementation-dependent"/> way. The effect is that it is
                     <termref def="implementation-dependent"/> which of the duplicates is chosen.
                  </fos:value>
                  <fos:value value='"combine"'
                        >Equivalent to supplying the function <code>fn($a, $b){ $a, $b }</code>
                     (or equivalently, the function <code>op(",")</code>).
                     The effect is that the result contains the <xtermref spec="XP40" ref="dt-sequence-concatenation"/>
                     of the values having the same key, retaining order.
                  </fos:value>
                  <fos:value value="function(*)">
                     A function with signature <code>fn(item()*, item()*) as item()*</code>.
                     The function is called for any entry in the input sequence that has the 
                     <termref def="dt-same-key"/> as a previous entry. The first argument
                     is the existing value associated with the key; the second argument
                     is the value associated with the key in the duplicate input entry,
                     and the result is the new value to be associated with the key. The effect
                     is cumulative: for example if there are three values <var>X</var>, <var>Y</var>,
                     and <var>Z</var> associated with the same key, and the supplied function is
                     <var>F</var>, then the result is an entry whose value is 
                     <code><var>X</var> => <var>F</var>(<var>Y</var>) => <var>F</var>(<var>Z</var>)</code>.
                  </fos:value>
               </fos:values>
                        
             </fos:option>

         </fos:options>


            </item>
         </ulist>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
for-each(
  $input, 
  fn($item, $pos) {
    for-each($key($item, $pos), fn($k) {
      map:entry($k, $value($item, $pos))
    }
  )}
)
=> map:merge($options)
      </fos:equivalent>
      <fos:errors>
         
         <p>An error is raised <errorref spec="FO" class="JS" code="0003"
               /> if the value of 
          <code>$options</code> indicates that duplicates are to be rejected, and a duplicate key is encountered.</p>
         <p>An error is raised <errorref spec="FO" class="JS" code="0005"
               /> if the value of 
          <code>$options</code> includes an entry whose key is defined 
          in this specification, and whose value is not a permitted value for that key.</p>
         
      </fos:errors>
      
      <fos:notes>

         <p>The default function for both <code>$key</code> and <code>$value</code> is the identity function.
            Although it is permitted to default both, this serves little purpose: usually at least one of these arguments
            will be supplied.</p>
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>map:build((), string#1)</fos:expression>
               <fos:result>{}</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>map:build(1 to 10, fn { . mod 3 })</fos:expression>
               <fos:result>{ 0: (3, 6, 9), 1: (1, 4, 7, 10), 2: (2, 5, 8) }</fos:result>
               <fos:postamble>Returns a map with one entry for each distinct value of <code>. mod 3</code>. The
                  function to compute the value is the identity function, and duplicates are combined by
                  sequence concatenation.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:build(
  1 to 5,
  value := format-integer(?, "w")
)</eg></fos:expression>
               <fos:result>{ 1: "one", 2: "two", 3: "three", 4: "four", 5: "five" }</fos:result>
               <fos:postamble>Returns a map with five entries. The function to compute the key is an identity function, the
                  function to compute the value invokes <function>fn:format-integer</function>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:build(
  ("January", "February", "March", "April", "May", "June",
   "July", "August", "September", "October", "November", "December"),
  substring(?, 1, 1)
)</eg></fos:expression>
               <fos:result>{
  "A": ("April", "August"),
  "D": ("December"),
  "F": ("February"),
  "J": ("January", "June", "July"),
  "M": ("March", "May"),
  "N": ("November"),
  "O": ("October"),
  "S": ("September")
}</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:build(1 to 5, {
  1: ("eins", "one"),
  4: ("vier", "four")
})</eg></fos:expression>
            <fos:result>{
  "eins": 1,
  "one": 1,
  "vier": 4,
  "four": 4
}</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:build(
  ("apple", "apricot", "banana", "blueberry", "cherry"), 
  substring(?, 1, 1),
  string-length#1,
  { "duplicates": op("+") }
)</eg></fos:expression>
               <fos:result>{ "a": 12, "b": 15, "c": 6 }</fos:result>
               <fos:postamble>Constructs a map where the key is the first character of an input item, and where the corresponding value
                  is the total string-length of the items starting with that character.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:build(
  ('Wang', 'Liu', 'Zhao'),
  key := fn($name, $pos) { $name },
  value := fn($name, $pos) { $pos }
)</eg></fos:expression>
               <fos:result>{ "Wang": 1, "Liu": 2, "Zhao": 3 }</fos:result>
               <fos:postamble>Returns an inverted index for the input sequence with the 
                  string stored as key and the position stored as value.</fos:postamble>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[
let $titles := <titles>
  <title>A Beginner’s Guide to <ix>Java</ix></title>
  <title>Learning <ix>XML</ix></title>
  <title>Using <ix>XML</ix> with <ix>Java</ix></title>
</titles>
return map:build($titles/title, fn($title) { $title/ix })
]]></eg></fos:expression>
               <fos:result><eg><![CDATA[{
  "Java": (
    <title>A Beginner’s Guide to <ix>Java</ix></title>,
    <title>Using <ix>XML</ix> with <ix>Java</ix></title>
  ),
  "XML": (
    <title>Learning <ix>XML</ix></title>,
    <title>Using <ix>XML</ix> with <ix>Java</ix></title>
  )
}]]></eg></fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <all-of>
                        <assert><![CDATA[?Java[1][self::title][ix='Java'][string(.)="A Beginner’s Guide to Java"]]]></assert>
                        <assert><![CDATA[?Java[2][self::title][ix='XML'][ix='Java'][string(.)="Using XML with Java"]]]></assert>
                        <assert><![CDATA[?XML[1][self::title][ix='XML'][string(.)="Learning XML"]]]></assert>
                        <assert><![CDATA[?XML[2][self::title][ix='XML'][ix='Java'][string(.)="Using XML with Java"]]]></assert>
                     </all-of>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:build(//employee, fn { @ssn })</eg></fos:expression>
               <fos:result narrative="true">A map whose keys are employee <code>@ssn</code> values, and whose
               corresponding values are the employee nodes</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:build(//employee, fn { @location }, fn { 1 }, { "duplicates": op("+") })</eg></fos:expression>
               <fos:result narrative="true">A map whose keys are employee <code>@location</code> values, and whose
               corresponding values represent the number of employees at each distinct location. Any employees that
               lack an <code>@location</code> attribute will be excluded from the result.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:build(
  //employee,
  key := fn { @location }, 
  options := { "duplicates": fn($a, $b) { highest(($a, $b), (), fn { xs:decimal(@salary) }) } }
)</eg></fos:expression>
               <fos:result narrative="true">A map whose keys are employee <code>@location</code> values, and whose
               corresponding values contain the employee node for the highest-paid employee at each distinct location</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
            
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:build(//*, generate-id#1)</eg></fos:expression>
               <fos:result narrative="true">A map allowing efficient access to every element in a document by means
               of its <function>fn:generate-id</function> value.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
 
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $tree := parse-json('{
  "type": "package",
  "name": "org",
  "content": [
      { "type": "package",
        "name": "xml",
        "content": [
            { "type": "package",
              "name": "sax",
              "content": [
                  { "type": "class",
                    "name": "Attributes"},
                  { "type": "class",
                    "name": "ContentHandler"},
                  { "type": "class",
                    "name": "XMLReader"}
               ]
            }]
       }]
   }')
   return map:build($tree/descendant-or-self::jnode(*, record(type, name, content?)),
                    fn{./ancestor-or-self::jnode()?name => string-join(".")},
                    fn{`{?type} {?name}`})
            </eg></fos:expression>
               <fos:result><eg>{ "org":"package org",
  "org.xml":"package xml",
  "org.xml.sax":"package sax",
  "org.xml.sax.Attributes": "class Attributes",
  "org.xml.sax.ContentHandler": "class ContentHandler",
  "org.xml.sax.XMLReader": "class XMLReader" }</eg></fos:result>
               <fos:postamble>Constructs a map allowing efficient access to values in a recursive JSON structure
               using hierarchic paths</fos:postamble>
            </fos:test>
       
            
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="151" PR="203" date="2022-10-18"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="size" prefix="map">
      <fos:signatures>
         <fos:proto name="size" return-type="xs:integer">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of entries in the supplied map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <function>map:size</function> takes any <termref def="dt-map"
               >map</termref>
            as its <code>$map</code> argument and returns the number of entries that are present
            in the map.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
count(map:entries($map))
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>map:size({})</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>map:size({ "true": 1, "false": 0 })</fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <!--<fos:function name="sort" prefix="map">
      <fos:signatures>
         <fos:proto name="sort" return-type="map(*)">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sorted map with the same entries as a supplied map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function <code>map:sort</code> takes any <termref def="dt-map"
               >map</termref>
            as its <code>$map</code> argument and returns a sorted map containing the
            same entries.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
map:of-pairs(map:pairs($map), { 'ordering': 'sorted' })
      </fos:equivalent>
      <fos:errors>
         <p>An error is raised <errorref spec="FO" class="JS" code="0008"/> if 
            the keys in <code>$map</code> are not 
         <termref def="dt-strictly-comparable"/>.</p>
      </fos:errors>
      <fos:notes>
         <p>If the <code>ordering</code> property of <code>$map</code> is <code>sorted</code>,
         then <code>$map</code> is returned unchanged.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>map:sort({ "a": 0, "z": 0, "q": 0 }) => map:keys()</fos:expression>
               <fos:result>"a", "q", "z"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>map:sort({}) => map:put("x", 0) => map:put("a", 0) => map:keys()</fos:expression>
               <fos:result>"a", "x"</fos:result>
               <fos:postamble>Adding entries to a sorted map, even if it is empty, produces a sorted map</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="564" PR="1609" date="2024-11-27"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>-->
   
   <!--<fos:function name="range" prefix="map">
      <fos:signatures>
         <fos:proto name="range" return-type="xs:integer">
            <fos:arg name="map" type="map(*)" usage="inspection"/>
            <fos:arg name="min" type="xs:anyAtomicType?" usage="absorption" default="()"/>
            <fos:arg name="max" type="xs:anyAtomicType?" usage="absorption" default="()"/>
            <fos:arg name="count" type="xs:integer?"  usage="absorption" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sorted map containing a subset of the entries of a supplied map.</p>
      </fos:summary>
      <fos:rules>
         <p>The function filters the supplied <code>$map</code> to return those entries that are
         within a given range of values.</p>
         <p>The function first selects those entries whose
            key <var>K</var> satisfies all the following conditions:</p>
       
         <ulist>
            <item><p>If <code>$min</code> is supplied, then <var>K</var> is 
               greater than or equal to <code>$min</code>.</p></item>
            <item><p>If <code>$max</code> is supplied, then <var>K</var> is 
               less than <code>$max</code>.</p></item>
         </ulist>
         
         <p>If <code>$count</code> is specified, then:</p>
         <ulist>
            <item><p>If <code>$count</code> is positive and is less than the number of selected
            entries, it then selects the first <code>$count</code> of these entries, in key order.</p></item>
            <item><p>If <code>$count</code> is negative and <code>-$count</code> is less than the number of selected
            entries, it then selects the last <code>-$count</code> of these entries, in key order.</p></item>
         </ulist>
         
         <p>For example, specifying <code>count := 1</code> selects the first qualifying entry, while
         <code>count := -1</code> selects the last.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
let $CC := "http://www.w3.org/2005/xpath-functions/collation/codepoint"         
let $pairs := map:pairs(map:sort($map)) [
   (empty($min) or compare(?key, $min, $CC) ge 0) and  
   (empty($max) or compare(?key, $max, $CC) lt 0)
]
let $slice := 
  if ($count gt 0) then slice($pairs, 1, $count)
  else if ($count lt 0) then slice($pairs, -$count, -1)
  else $pairs
return
  map:of-pairs($slice, { "ordering": "sorted" })
</fos:equivalent>
      <fos:errors>
         <p>An error is raised <errorref spec="FO" class="JS" code="0008"/> if 
            the keys in <code>$map</code> are not 
         <termref def="dt-strictly-comparable"/>.</p>
      </fos:errors>
      <fos:notes>
         <p>The function is intended primarily to take advantage of efficiencies that
            become possible when the supplied <code>$map</code> has <code>ordering=sorted</code>,
            but it still works if the input is not sorted. </p>
         <p>Note that <code>$min</code> is an inclusive bound, while <code>$max</code> is exclusive.
         If <code>$min</code> is omitted, the selection starts at the first entry in <code>$map</code>,
         and if <code>$max</code> is omitted, the selection ends at the last entry.</p>
      </fos:notes>
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression><eg>map:sort({ "a": 1, "c": 3, "b": 2 }) => map:range(count:=1) </eg></fos:expression>
               <fos:result><eg>{ "a": 1 }</eg></fos:result>
               <fos:postamble>Selects the first entry in the map, in key order</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:sort({ "a": 1, "c": 3, "b": 2 }) => map:range(count:=-1) </eg></fos:expression>
               <fos:result><eg>{ "c": 3 }</eg></fos:result>
               <fos:postamble>Selects the last entry in the map, in key order</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:sort({ "a": 1, "c": 3, "b": 2 }) => map:range(max:="b") </eg></fos:expression>
               <fos:result><eg>{ "a": 1, "b": 2 }</eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eeg>map:sort({ "a": 1, "c": 3, "b": 2 }) => map:range(min:="b", max="d") </eeg></fos:expression>
               <fos:result><eg>{ "b": 2, "c": 3 }</eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>map:sort({ "aa": 1, "cc": 3, "bb": 2 }) 
=> map:range(min:="b", count:=1) 
=> map:keys() </eg></fos:expression>
               <fos:result><eg>"bb"</eg></fos:result>
               <fos:postamble>Returns the first key greater than or equal to the supplied value.</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="564" PR="1609" date="2024-11-27"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>-->

   <fos:function name="collation" prefix="fn">
      <fos:signatures>
         <fos:proto name="collation" return-type="xs:string">
            <fos:arg name="options" type="map(*)"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Constructs a collation URI with requested properties.</p>
      </fos:summary>
      <fos:rules>
         <p>The function is supplied with a map defining the properties required of 
            the collation, and returns a collation URI with these properties.</p>
         
         <p>Specifically, it returns a string in the form of a URI with the scheme and path
               <code>http://www.w3.org/2013/collation/UCA</code> followed by an optional 
               query part. The query part is absent if <code>options</code> is empty.
               Otherwise it consists of a question mark followed 
               by a sequence of one or more semicolon-separated parameters. Each parameter 
               is a keyword-value pair, the keyword and value being separated by an equals sign.
               There is one keyword-value pair for each entry in the <code>options</code> map: 
               the keyword is the same as the string value of the key in the map, and the value
               is the string value of the corresponding value, except where the value is of
               type <code>xs:boolean</code>, in which case <code>true</code> and <code>false</code>
               are translated to <code>yes</code> and <code>no</code>.
            </p>
         
         <p>The function does not check whether the implementation actually recognizes
         the resulting collation URI: that can be achieved using the <function>fn:collation-available</function>
         function.</p>
         
         
         <p>The properties available are as defined for the Unicode Collation Algorithm 
            (see <specref ref="uca-collations"/>). Additional <termref def="implementation-defined"/>
            properties <rfc2119>may</rfc2119> be specified  as described in the rules for UCA 
            collation URIs.</p>
         
         <p>The <termref def="option-parameter-conventions">option parameter conventions</termref> 
            apply, except as regards the handling of options not defined in this specification.
            Specifically:</p>
         
         <ulist>
            <item><p>If the option key is of type <code>xs:string</code>, <code>xs:anyURI</code>,
            or <code>xs:untypedAtomic</code> then it is converted to a string, and produces
               a URI query parameter which is handled as described in  <specref ref="uca-collations"/>.
            </p></item>
            <item><p>If the option key is of any other type then the function fails with a
               type error <xerrorref spec="XP" class="TY" code="0004"/>.</p></item>
         </ulist>
         
         <p>The following options are defined:</p>
         
         <fos:options>
            <fos:option key="fallback">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
            </fos:option>
            <fos:option key="lang">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:language</fos:type>
               <fos:default>default-language()</fos:default>
            </fos:option>
            <fos:option key="version">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="strength">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>enum("primary", "secondary", "tertiary",
               "quaternary", "identical", "1", "2", "3", "4", "5")</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="maxVariable">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>enum("space", "punct", "symbol",
                  "currency")</fos:type>
               <fos:default>"punct"</fos:default>
            </fos:option>
            <fos:option key="alternate">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>enum("non-ignorable", "shifted", "blanked",
                  "currency")</fos:type>
               <fos:default>"non-ignorable"</fos:default>
            </fos:option>
            <fos:option key="backwards">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="normalization">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="caseLevel">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="caseFirst">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>enum("upper","lower")</fos:type>
               <fos:default>"lower"</fos:default>
            </fos:option>
            <fos:option key="numeric">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="reorder">
               <fos:meaning>See <specref ref="uca-collations"/>.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>""</fos:default>
            </fos:option>
            
         </fos:options>
         
         
         
         
      </fos:rules>
      <fos:errors>

         <p>A type error is raised <xerrorref spec="XP" class="TY" code="0004"/> if 
            <code>options</code> includes an entry whose key is not of
            type <code>xs:string</code>, <code>xs:anyURI</code>,
            or <code>xs:untypedAtomic</code>, or whose corresponding value
            is not castable to <code>xs:string</code>.</p>
      </fos:errors>

      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression>collation({})</fos:expression>
               <fos:result>"http://www.w3.org/2013/collation/UCA"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>collation({ 'lang': 'de' })</fos:expression>
               <fos:result>"http://www.w3.org/2013/collation/UCA?lang=de"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>collation({ 'lang': 'de', 'strength': 'primary' })</fos:expression>
               <fos:result>"http://www.w3.org/2013/collation/UCA?lang=de;strength=primary"</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <any-of>
                        <assert-string-value>http://www.w3.org/2013/collation/UCA?lang=de;strength=primary</assert-string-value>
                        <assert-string-value>http://www.w3.org/2013/collation/UCA?strength=primary;lang=de;</assert-string-value>
                     </any-of>
                  </result>
               </fos:test-assertion>
               <fos:postamble>The order of query parameters may vary.</fos:postamble>
            </fos:test>
            
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>collation({ 'lang': default-language() })</fos:expression>
               <fos:result narrative="true">A collation suitable for the default language in the
               dynamic context.</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1091" PR="1093" date="2024-04-09"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="collation-available" prefix="fn">
      <fos:signatures>
         <fos:proto name="collation-available" return-type="xs:boolean">
            <fos:arg name="collation" type="xs:string"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Asks whether a collation URI is recognized by the implementation.</p>
      </fos:summary>
      <fos:rules>
         <p>The supplied argument is a candidate collation URI.</p>
         <p>The function returns true if and only if the implementation recognizes the candidate
            collation URI.</p>
      </fos:rules>
      <fos:notes>
         <p>If the candidate collation is a UCA collation specifying <code>fallback=yes</code>,
         then this function will always return true: implementations are required to recognize
         such a collation and use fallback behavior if there is no direct equivalent available.</p>
      </fos:notes>

      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression>collation-available("http://www.w3.org/2013/collation/UCA?lang=de")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>collation({ 'lang': 'de' }) => collation-available()</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1160" PR="1262" date="2024-07-09"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="collation-key" prefix="fn">
      <fos:signatures>
         <fos:proto name="collation-key" return-type="xs:base64Binary">
            <fos:arg name="value" type="xs:string"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Given a string value and a collation, generates an internal value called a collation key, with the property that
            the matching and ordering of collation keys reflects the matching and ordering of strings under the specified collation.</p>
      </fos:summary>
      <fos:rules>
         <p>Calling the one-argument version of this function is equivalent to calling the
            two-argument version supplying the default collation as the second argument.</p>
         <p>The function returns an <termref def="implementation-dependent"
               >implementation-dependent</termref> 
            value with the property that,
            for any two strings <code>$K1</code> and <code>$K2</code>:</p>
         <ulist>
            <item>
               <p><code>collation-key($K1, $C) eq collation-key($K2, $C)</code> if and only if
                  <code>compare($K1, $K2, $C) eq 0</code></p>
            </item>
            <item>
               <p><code>collation-key($K1, $C) lt collation-key($K2, $C)</code> if and only if
                  <code>compare($K1, $K2, $C) lt 0</code></p>
            </item>
         </ulist>

         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"
               />. Collation keys are defined as <code>xs:base64Binary</code> values
            to ensure unambiguous and context-free comparison semantics.</p>
         <p>An implementation is free to generate a collation key in any convenient way provided
            that it always generates the same collation key for two strings that are equal under the
            collation, and different collation keys for strings that are not equal. This holds only
            within a single <termref
               def="execution-scope"
            >execution scope</termref>;
            an implementation is under no obligation to generate the same collation keys during a
            subsequent unrelated query or transformation.</p>
         <p>It is possible to define collations that do not have the ability to generate collation
            keys. Supplying such a collation will cause the function to fail. The ability to
            generate collation keys is an <termref
               def="implementation-defined"
            >implementation-defined</termref> property of the
            collation.</p>
      </fos:rules>
      <fos:errors>
         <p>An error is raised <errorref class="CH" code="0004"
            /> if the specified
            collation does not support the generation of collation keys. </p>
      </fos:errors>
      <fos:notes>
         <p>The function is provided primarily for use with maps. If a map is required where
            codepoint equality is inappropriate for comparing keys, then a common technique is to
            normalize the key so that equality matching becomes feasible. There are many ways
            keys can be normalized, for example by use of functions such as
               <function>fn:upper-case</function>, <function>fn:lower-case</function>,
               <function>fn:normalize-space</function>, or <function>fn:normalize-unicode</function>, but this
            function provides a way of normalizing them according to the rules of a specified
            collation. For example, if the collation ignores accents, then the function will
            generate the same collation key for two input strings that differ only in their use of
            accents.</p>
         <p>The result of the function is defined to be an <code>xs:base64Binary</code> value. Binary values
         are chosen because they have unambiguous and context-free comparison semantics, because the value space
         is unbounded, and because the ordering rules are such that between any two values in the ordered value space, an
         arbitrary number of further values can be interpolated. The choice between <code>xs:base64Binary</code>
            and <code>xs:hexBinary</code> is arbitrary; the only operation that behaves differently between the two binary
            data types is conversion to/from a string, and this operation is not one that is normally required for
            effective use of collation keys.
         </p>
         <p>For collations based on the Unicode Collation Algorithm, an algorithm for computing
            collation keys is provided in <bibref
               ref="UNICODE-TR10"
               />. Implementations are
               <rfc2119>not required</rfc2119> to use this algorithm.</p>

         <p>The fact that collation keys are ordered can be exploited in XQuery, whose <code>order by</code>
         clause does not allow the collation to be selected dynamically. This restriction can be circumvented
         by rewriting the clause <code>order by $e/@key collation "URI"</code> as <code>order by fn:collation-key($e/@key, $collation)</code>,
         where <code>$collation</code> allows the collation to be chosen dynamically.</p>
         <p>Note that <code>xs:base64Binary</code> becomes an ordered type
         in XPath 3.1, making binary collation keys possible.</p>
         
         <p>The <function>fn:collation-available</function> can be used to ask whether a particular
         collation is capable of delivering collation keys.</p>

      </fos:notes>
      <fos:examples>
         <fos:variable name="C" id="v-collation-key-C"
            select="collation({ 'strength': 'primary' })"/>
         <fos:example>
            <fos:test use="v-collation-key-C">
               <fos:expression><eg>map:merge(
  ({ collation-key("A", $C): 1 }, { collation-key("a", $C): 2 }),
  { "duplicates": "use-last" }
)(collation-key("A", $C))</eg></fos:expression>
               <fos:result>2</fos:result>
               <fos:postamble>Given that the keys of the two entries are equal under the rules of
                  the chosen collation, only one of the entries can appear in the result; the one
                  that is chosen is the one from the last map in the input sequence.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test use="v-collation-key-C">
               <fos:expression><eg>let $M := {
  collation-key("A", $C): 1,
  collation-key("B", $C): 2
}
return $M(collation-key("a", $C))</eg></fos:expression>
               <fos:result>1</fos:result>
               <fos:postamble>The strings <code>"A"</code> and <code>"a"</code> have the same collation key under this
                  collation.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>As the above examples illustrate, it is important that when the
                  <code>collation-key</code> function is used to add entries to a map, then it must
               also be used when retrieving entries from the map. This process can be made less
               error-prone by encapsulating the map within a function:
               <code>fn($k) { $M(collation-key($k, $collation) }</code>.</p>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="json-to-xml" prefix="fn">
      <fos:signatures>
         <fos:proto name="json-to-xml" return-type="document-node(fn:*)?">
            <fos:arg name="value" type="xs:string?" example="'[22, 23]'"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Parses a string supplied in the form of a JSON text, returning the results in the form
            of an XML <phrase>document node</phrase>.</p>
      </fos:summary>
      <fos:rules>
         <p>The first argument is a JSON text as defined in <bibref ref="rfc7159"
            />, in the form of a string. The function
            parses this string to return an XDM node.</p>

         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>

         <p>The <code>$options</code> argument can be used to control the way in which the parsing
            takes place. The <termref
               def="option-parameter-conventions">option parameter conventions</termref> apply.</p>

         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>

         <fos:options>
            <fos:option key="liberal">
               <fos:meaning>Determines whether deviations from the syntax of RFC7159 are permitted.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false"
                        >
                     The input <rfc2119>must</rfc2119> consist of <phrase>an optional byte order mark (which is ignored) followed by</phrase> a string
                     that conforms to the grammar of <code>JSON-text</code> in <bibref
                        ref="rfc7159"
                     />. An error <rfc2119>must</rfc2119> be raised
                     (see below) if the input does not conform to the grammar.
                  </fos:value>
                  <fos:value value="true"
                        >
                     The input <rfc2119>may</rfc2119> contain deviations from the grammar of <bibref
                        ref="rfc7159"/>,
                     which are handled in an <termref
                        def="implementation-defined"
                        >implementation-defined</termref> way. (Note: some popular
                     extensions include allowing quotes on keys to be omitted, allowing a comma
                     to appear after the last item in an array, allowing leading zeroes in numbers, and allowing control characters such as
                     tab and newline to be present in unescaped form.) Since the extensions accepted
                     are implementation-defined, an error <rfc2119>may</rfc2119> be raised
                     (see below) if the input does not conform to the grammar.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="duplicates">
               <fos:meaning>Determines the policy for handling duplicate keys in a JSON object.
                  To determine whether keys are duplicates, they are compared using the Unicode codepoint collation, after expanding escape
                  sequences, unless the <phrase><code>escape</code> option is set to <code>true</code></phrase>, in which
                  case keys are compared in escaped form. 
               </fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default-description>If <code>validate</code> is <code>true</code> then <code>reject</code>, otherwise <code>retain</code>.</fos:default-description>
               <fos:values>
                  <fos:value value="reject">
                     An error is raised <errorref
                        class="JS" code="0003"
                     /> if duplicate keys are encountered.
                  </fos:value>
                  <fos:value value="use-first"
                     >
                     If duplicate keys are present in a JSON object, all but the first of a set of duplicates are ignored.
                  </fos:value>
                  <fos:value value="retain"
                        >
                     If duplicate keys are present in a JSON object, the XML result of the function will also contain duplicates (making
                     it invalid against the schema). This value is therefore incompatible with the option <code>validate=true</code>
                     <errorref class="JS" code="0005"/>
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="validate">
               <fos:meaning>Determines whether the generated XML tree is schema-validated.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default-description><termref def="implementation-defined">Implementation-defined</termref>.</fos:default-description>
               <fos:values>
                  <fos:value value="true"
                        >
                     Indicates that the resulting XDM instance must be typed; that is, the element
                     and attribute nodes must carry the type annotations that result from validation
                     against the schema given at <specref
                        ref="schema-for-json"/>, or against an
                     <termref
                        def="implementation-defined"
                        >implementation-defined</termref> schema 
                     if the <code>liberal</code> option has the value <code>true</code>.
                  </fos:value>
                  <fos:value value="false"
                     >
                     Indicates that the resulting XDM instance must be untyped.
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="escape">
               <fos:meaning>Determines whether special characters are represented in the XDM output 
                  in backslash-escaped form. </fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">
                     All characters in the input that are valid
                     in the version of XML supported by the implementation, whether or not they are represented 
                     in the input by means of an escape sequence, are represented as unescaped characters in the result. Any
                     characters or codepoints that are not valid XML characters 
                     (for example, unpaired surrogates) <phrase>are passed to the <code>fallback</code> function
                        as described below; in the absence of a fallback function, they are replaced by
                        the character <char>U+FFFD</char></phrase>.
                     The attributes <code>escaped</code> and <code>escaped-key</code> will not be present in the XDM output.
                  </fos:value>
                  <fos:value value="true">
                     JSON escape sequences are used in the result to represent special characters in the JSON input, as defined below, 
                     whether or not they were represented using JSON escape sequences in the input.
                     The characters that are considered “special” for this purpose are:
                     <ulist>
                        <item><p>all codepoints in the range <char>U+0000</char> to <char>U+001F</char> 
                           or <char>U+007F</char> to <char>U+009F</char>;</p></item>
                        <item><p>all codepoints that do not represent characters that are valid in the version of XML supported by the processor,
                           including codepoints representing unpaired surrogates;</p></item>
                        <item><p>the backslash character itself (<char>U+005C</char>).</p></item>
                     </ulist>
                     
                     Such characters are represented using a two-character
                     escape sequence where available (for example, <code>\t</code>), or a six-character escape sequence otherwise
                     (for example <code>\uDEAD</code>). Characters other than these will not be escaped in the result,
                     even if they were escaped in the input. In the result:
                     
                     <ulist>
                        <item><p>Any <code>string</code> element whose string value contains a
                           backslash character must have the attribute value <code>escaped="true"</code>.</p></item>
                        <item><p>Any element that contains a <code>key</code> attribute whose string value
                           contains a backslash character must have the attribute
                           <code>escaped-key="true"</code>.</p></item>
                        <item><p>The values of the <code>escaped</code> and
                           <code>escaped-key</code> attributes are immaterial when there is no backslash
                           present, and it is never necessary to include either attribute when its value
                           is <code>false</code>.</p></item>
                     </ulist>
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="fallback">
               <fos:meaning>
                  Provides a function which is called when the input contains an escape sequence 
                  that represents a character that is not valid in the version of XML
                  supported by the implementation. 
                  It is an error to supply the <code>fallback</code> option if the <code>escape</code>
                  option is present with the value <code>true</code>.
               </fos:meaning>
               <fos:type>(fn(xs:string) as xs:anyAtomicType)?</fos:type>
               <fos:default>fn { char(0xFFFD) }</fos:default>
               <fos:values>
                  <fos:value value="User-supplied function">
                     The function is called when the JSON input contains an escape sequence
                     that is valid according to the JSON grammar, but which does not represent a
                     character that is valid in the version of XML supported by the processor.
                     In the case of surrogates, it is called once for any six-character escape sequence
                     that is not properly paired with another surrogate. The untyped atomic item
                     supplied as the argument will always be a two- or six-character escape
                     sequence, starting with a backslash, that conforms to the rules in the JSON grammar
                     (as extended by the implementation if <code>liberal:true()</code> is specified):
                     for example <code>\b</code> or <code>\uFFFF</code> or <code>\uDEAD</code>.
                     <p>By default, the escape sequence is replaced with the Unicode
                     <code>REPLACEMENT CHARACTER</code>. The function is <emph>not</emph>
                     called for an escape sequence that is invalid against the grammar (for example <code>\x0A</code>). 
                     The string, which results from invoking <function>fn:string</function> on the result
                     of the function, is inserted into the result in place of the invalid character. The
                     function also has the option of raising a dynamic error by calling <function>fn:error</function>.</p>
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="number-parser" diff="add" at="A">
               <fos:meaning>Determines how numeric values should be processed.</fos:meaning>
               <fos:type>(fn(xs:untypedAtomic) as item()?)?</fos:type>
               <fos:default>xs:identity#1</fos:default>
               <fos:values>
                  <fos:value value="User-supplied function">
                     The supplied function is called to process the string value of any JSON number
                     in the input. The string value of the <code>number</code> element generated in
                     the result will be the value obtained by calling the supplied function, and
                     then converting its result to a string by calling <code>fn:string#1</code>.
                     <p>By default, numbers are represented in the XML output exactly as they
                        were written in the input.
                     Supplying the value <code>xs:double#1</code> will cause the value to be
                        convered to type <code>xs:double</code> (which will then be represented
                        in the XML by converting the <code>xs:double</code> to a string).
                        Similarly <code>xs:decimal#1</code> will convert to <code>xs:decimal</code>
                     (which potentially retains more precision, but disallows exponential notation), while
                     supplying a function that casts to <code>(xs:decimal | xs:double)</code> will treat
                     the value as <code>xs:decimal</code> if there is no exponent, or as <code>xs:double</code>
                     otherwise. The default value <code>fn:identity#1</code> causes the value to be retained
                     unchanged as an <code>xs:untypedAtomic</code>. Before calling the supplied <code>number-parser</code>,
                     the value is first checked to ensure that it conforms to the JSON grammar (for example,
                     a leading plus sign and redundant leading zeroes are not allowed); these checks are disabled
                     if the <code>liberal</code> option is set to <code>true</code>. Note that the
                     option <code>validate=true</code> will cause the result to be validated
                     as type <code>xs:double</code> (disallowing NaN and infinity).</p>
                  </fos:value>
               </fos:values>
            </fos:option>
         </fos:options>

         <p>The various structures that can occur in JSON are transformed recursively to XDM values
            according to the rules given in <specref
               ref="json-to-xml-mapping"/>.</p>

         <p>The function returns a document node, whose only child
               is the element node representing the outermost construct in the JSON
            text.</p>

         <p>The function is <termref def="dt-nondeterministic"
               >nondeterministic with respect to node identity</termref>: that is, if the function is called twice with the same
            arguments, it is <termref
               def="implementation-dependent"
            >implementation-dependent</termref> whether the same node is returned on both
            occasions.</p>

         <p>The base URI of the returned document node is taken from the 
            <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> of the
            function call.</p>

         <p>The choice of namespace prefix (or absence of a prefix) in the names of constructed
         nodes is <termref
               def="implementation-dependent">implementation-dependent</termref>.</p>

         <p>The XDM tree returned by the function does not contain any
         unnecessary (albeit valid) nodes such as whitespace text nodes, comments, or processing instructions.
         It does not include any whitespace in the value of <code>number</code> or <code>boolean</code> 
            element nodes, nor in the value of <code>escaped</code> or <code>escaped-key</code>
         attribute nodes.</p>


         <p>If the result is typed, every element named <code>string</code> will have an attribute named 
            <code>escaped</code> whose value is either <code>true</code> or <code>false</code>, and every element having 
            an attribute named <code>key</code> will also have an attribute named <code>escaped-key</code> whose value is either 
            <code>true</code> or <code>false</code>.
         </p>
         <p>If the result is untyped, the attributes <code>escaped</code> and <code>escaped-key</code> will 
            either be present with the value <code>true</code>, or will be absent. They will never be present with the value <code>false</code>.</p>

      </fos:rules>
      <fos:errors>

         <p>An error is raised <errorref spec="FO" class="JS" code="0001"
               /> if the value of
            <code>$value</code> does not conform to the JSON grammar as defined
            by <bibref
               ref="rfc7159"
            />, unless the option <code>"liberal":true()</code> is present and
            the processor chooses to accept the deviation. </p>

         <p>An error is raised <errorref spec="FO" class="JS" code="0004"
               /> if the value of
            the <code>validate</code> option is <code>true</code> and the processor does not support
            schema validation or typed data.</p>

         <p>An error is raised <errorref spec="FO" class="JS" code="0005"
               /> if the value of
            <code>$options</code> includes an entry whose key is defined in this specification,
               and whose value is not a permitted value for that key.</p>


      </fos:errors>
      <fos:notes>
         <p>To read a JSON file, this function can be used in conjunction with the
               <function>fn:unparsed-text</function> function.</p>
         <p>Many JSON implementations allow commas to be used after the last item in an object or
            array, although the specification does not permit it. The option
               <code>spec="liberal"</code> is provided to allow such deviations from the
            specification to be accepted. Some JSON implementations also allow constructors such as
               <code>new Date("2000-12-13")</code> to appear as values: specifying
               <code>spec="liberal"</code> allows such extensions to be accepted, but does not
            guarantee it. If such extensions are accepted, the resulting value is
            implementation-defined, and will not necessarily conform to the schema at <specref
               ref="schema-for-json"/>.</p>
         <p>If the input starts with a byte order mark, this function ignores it. The byte order mark may have been added
            to the data stream in order to facilitate decoding of an octet stream to a character string, but since this function
            takes a character string as input, the byte order mark serves no useful purpose.</p>
         <p>The possibility of the input containing characters that are not valid in XML (for example, unpaired surrogates)
         arises only when such characters are expressed using JSON escape sequences. This is the only possibility because the input to the function
         is an instance of <code>xs:string</code>, which by definition can contain only those characters that are valid in XML.</p>

      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>json-to-xml(
  '{ "x": 1, "y": [ 3, 4, 5 ] }',
  { "validate": false() }
)</eg></fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true"><![CDATA[
<map xmlns="http://www.w3.org/2005/xpath-functions">
  <number key="x">1</number>
  <array key="y">
   <number>3</number>
   <number>4</number>
   <number>5</number>
  </array>
</map>]]></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>json-to-xml(
  '"abcd"',
  { 'liberal': false() }
)</eg></fos:expression>
               <fos:result ignore-prefixes="true"
                  ><![CDATA[<string xmlns="http://www.w3.org/2005/xpath-functions">abcd</string>]]></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>json-to-xml(
  '{ "x": "\\", "y": "\u0025" }',
  { "validate": false() }
)</eg></fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true"><![CDATA[
<map xmlns="http://www.w3.org/2005/xpath-functions">
  <string key="x">\</string>
  <string key="y">%</string>
</map>]]></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>json-to-xml(
  '{ "x": "\\", "y": "\u0025" }',
  { 'escape': true(), "validate": false() }
)</eg></fos:expression>
               <fos:result normalize-space="true" ignore-prefixes="true"><![CDATA[
<map xmlns="http://www.w3.org/2005/xpath-functions">
  <string escaped="true" key="x">\\</string>
  <string key="y">%</string>
</map>]]></fos:result>
               <fos:postamble>But see the detailed rules for alternative values of the <code>escaped</code> attribute
                  on the second <code>string</code> element.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>The following example illustrates use of the <code>fallback</code> function to
               handle characters that are invalid in XML.</p>
            <eg><![CDATA[
let $json := unparsed-text('http://example.com/endpoint')
let $options := {
  'liberal': true(),
  'fallback': fn($char as xs:string) as xs:string {
    let $c0chars := {
      '\u0000': '[NUL]',
      '\u0001': '[SOH]',
      '\u0002': '[STX]',
      ...
      '\u001E': '[RS]',
      '\u001F': '[US]'
    }
    let $replacement := $c0chars($char)
    return if (exists($replacement)) then (
      $replacement
    ) else (
      error( #err:invalid-char,
        'Error: ' || $char || ' is not a C0 control character.'
      )
    )
  }
}
return json-to-xml($json, $options)]]></eg>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="xml-to-json" prefix="fn">
      <fos:signatures>
         <fos:proto name="xml-to-json" return-type="xs:string?">
            <fos:arg name="node" type="node()?" usage="absorption" example="()"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Converts an XML tree, whose format corresponds to the XML representation of JSON defined
            in this specification, into a string conforming to the JSON grammar.</p>
      </fos:summary>
      <fos:rules>
         <p>The first argument <code>$node</code> is a node; the subtree rooted at this node will typically be
            the XML representation of a JSON document as defined in <specref
               ref="json-to-xml-mapping"/>.</p>

         <p>If <code>$node</code> is the empty sequence, the function returns the empty sequence.</p>

         <p>The <code>$options</code> argument can be used to control the way in which the conversion
            takes place. The <termref
               def="option-parameter-conventions">option parameter conventions</termref> apply.</p>

         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>
        

         <fos:options>
            <fos:option key="escape-solidus">
               <fos:meaning>Determines whether the character <char>U+002F</char> should be escaped 
                  as <code>\/</code>. By default the character is escaped, but this is only necessary
                  when the resulting JSON is embedded in HTML.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
               <fos:values>
                  <fos:value value="false"
                     >
                     The character <char>U+002F</char> is output as is, without escaping.
                  </fos:value>
                  <fos:value value="true"
                     >
                     The character <char>U+002F</char> is escaped by preceding it with <char>U+005C</char>. 
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="indent">
               <fos:meaning>Determines whether additional whitespace should be added to the output to improve readability.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false"
                     >
                     The processor must not insert any insignificant whitespace between JSON tokens.
                  </fos:value>
                  <fos:value value="true"
                     >
                     The processor <rfc2119>may</rfc2119> insert whitespace between JSON tokens in order to improve readability.
                     The specification imposes no constraints on how this is done.
                  </fos:value>
               </fos:values>
            </fos:option>
         </fos:options>

 

         <p>The node supplied as <code>$node</code> must be one of the following: <errorref
               spec="FO" class="JS" code="0006"/></p>

         <olist>
            <item>
               <p>An element node whose name matches the name of a global element declaration in the schema given in 
               <specref
                     ref="schema-for-json"/> (“the schema”) and that is valid as defined below:</p>
               <olist>
                  <item>
                     <p>If the type annotation of the element matches the type of the relevant element declaration 
                     in the schema (indicating that the element has been validated against the schema), then the element 
                     is considered valid.
                  </p>
                  </item>
                  <item>
                     <p>Otherwise, the processor <rfc2119>may</rfc2119> attempt to validate the element against
                     the schema, in which case it is treated as valid if and only if the outcome of validation is
                     <term>valid</term>.
                  </p>
                  </item>
                  <item>
                     <p>Otherwise (if the processor does not attempt validation using the schema), 
                     the processor <rfc2119>must</rfc2119> ensure that the content of the element, 
                     after stripping all attributes (at any depth) in namespaces other than 
                     <code>http://www.w3.org/2005/xpath-functions</code>, is such that validation 
                     against the schema would have an outcome of <term>valid</term>.
                  </p>
                     <note>
                        <p>The process described here is not precisely equivalent to schema validation. 
                        For example, schema validation will fail if there is an invalid <code>xsi:type</code> 
                        or <code>xsi:nil</code> attribute, whereas this process will ignore such attributes.
                     </p>
                     </note>
                  </item>
               </olist>

            </item>

            <item>
               <p>An element node <var>E</var> having a <code>key</code> attribute and/or an <code>escaped-key</code> attribute 
               provided that <var>E</var> would satisfy one of the above
            conditions if the <code>key</code> and/or <code>escaped-key</code> attributes were removed.</p>

            </item>

            <item>
               <p>A document node having exactly one element child and no text node children, 
               where the element child satisfies one of the conditions above.</p>
            </item>
         </olist>



         <p><!--bug 29588-->Furthermore, <code>$node</code> must satisfy the following constraint
            (which cannot be conveniently expressed in the schema). Every element <var>M</var> that is a descendant-or-self of 
            <code>$node</code> and has local name <code>map</code> and namespace URI <code>http://www.w3.org/2005/xpath-functions</code>
            must satisfy the following rule: there must not be two distinct children of <var>M</var> (say <var>C/1</var> and <var>C/2</var>) 
            such that the normalized key of <var>C/1</var> is equal to the normalized key of <var>C/2</var>. The normalized key 
            of an element <var>C</var> is as follows:</p>

         <ulist>
            <item>
               <p>If <var>C</var> has the attribute value <code>escaped-key="true"</code>, then the value of the 
               <code>key</code> attribute of <var>C</var>, with all JSON escape sequences replaced by the corresponding Unicode characters 
               according to the JSON escaping rules.
            </p>
            </item>
            <item>
               <p>Otherwise (the <code>escaped-key</code> attribute of <var>C</var> is absent or set to <code>false</code>), 
               the value of the <code>key</code> attribute of <var>C</var>.</p>
            </item>
         </ulist>

         <p>Nodes in the input tree are handled by applying the following rules, recursively. In these rules the phrase
            “an element named <var>N</var>” means “an element node whose local name is <var>N</var> and whose namespace URI is 
            <code>http://www.w3.org/2005/xpath-functions</code>”.</p>

         <olist>
            <item>
               <p>A document node having a single element node child is processed by processing that child.</p>
            </item>
            <item>
               <p>An element named <code>null</code> results in the output <code>null</code>.</p>
            </item>
            <item>
               <p>An element <code>$E</code> named <code>boolean</code> results in the output <code>true</code> or <code>false</code>
            depending on the result of <phrase><code>xs:boolean(fn:string($E))</code></phrase>.</p>
            </item>
            <item>
               <p>An element <code>$E</code> named <code>number</code> is processed as follows.</p>
               
               <p>The input is required to conform to the XSD rules defining a valid instance of <code>xs:double</code>
               (excluding infinity and <code>NaN</code>), while the output is required to conform to the
               JSON rules defining a valid JSON number. These rules are slightly different.</p>
               
               <p>Specifically, the XSD rules require the value (after removing leading and trailing whitespace)
                  to match the regular expression:</p>
               
               <eg>(\+|-)?([0-9]+(\.[0-9]*)?|\.[0-9]+)([Ee](\+|-)?[0-9]+)?</eg>
               
               <p>while the JSON rules require:</p>
               
               <eg>-?(0|[1-9][0-9]*)(\.[0-9]+)?([Ee](\+|-)?[0-9]+)?</eg>
               
               <p>If the input value does not match the required JSON format, it must therefore be adjusted
               by applying the following steps:</p>
                  <ulist>
                     <item><p>Remove leading and trailing whitespace.</p></item>
                     <item><p>Remove any leading plus sign.</p></item>
                     <item><p>Remove any leading zero digits in the integer part, while ensuring that at
                        least one digit remains.</p></item>
                     <item><p>If there is a decimal point that is not preceded by a digit, add a zero digit 
                        before the decimal point.</p></item>
                     <item><p>If there is a decimal point that is not followed by a digit, add a zero digit 
                        after the decimal point.</p></item>
                  </ulist>
               
               <note>
                  <p>The output uses exponential notation if and only if the input uses exponential notation.</p>
                  <p>The rules have changed since version 3.1 of this specification. In previous versions, the supplied
                     number was cast to an <code>xs:double</code>, and then serialized using the rules of the 
                     <function>fn:string</function> function. This resulted in JSON numbers using exponential notation
                     for values outside the range 1e-6 to 1e6, and led to a loss of precision for 64-bit integer
                     values.                 
                  </p>
               </note>
            </item>
            <item>
               <p>An element named <code>string</code> results in the output of the string value of the element, enclosed in
            quotation marks, with any special characters in the string escaped as described below.</p>
            </item>
            <item>
               <p>An element named <code>array</code> results in the output of the children of the <code>array</code> element, 
               each processed by applying these rules recursively: the items in the resulting list are enclosed between square brackets, 
               and separated by commas.</p>
            </item>
            <item>
               <p>An element named <code>map</code> results in the output of a sequence of map entries corresponding to 
               the children of the <code>map</code> element, enclosed between curly braces and separated by commas. 
               Each entry comprises the value of the <code>key</code> attribute of the child element, enclosed in quotation marks 
               and escaped as described below, followed by a colon, followed by the result of processing the child element 
               by applying these rules recursively. The order of properties in the output JSON representation retains the order
               of the children of the <code>map</code> element.</p>
            </item>
            <item>
               <p>Comments, processing instructions, and whitespace text node children of <code>map</code> and <code>array</code>
               are ignored.</p>
            </item>

         </olist>

         <p>Strings are escaped as follows:</p>

         <olist>
            <item>
               <p>If the attribute <code>escaped="true"</code> is present for a string value, or <code>escaped-key="true"</code> for a key value, then:</p>

               <olist>
                  <item>
                     <p>any valid JSON escape sequence present in the string is copied unchanged to the output;</p>
                  </item>

                  <item>
                     <p>any invalid JSON escape sequence results in a dynamic error <errorref
                           spec="FO" class="JS" code="0007"/>;</p>
                  </item>

                  <item>
                     <p>any unescaped occurrence of <char>U+0022</char>, <char>U+0008</char>, <char>U+000C</char>, 
                        <char>U+000A</char>, <char>U+000D</char>, <char>U+0009</char>, or 
                        (subject to the <code>escape-solidus</code> option) <char>U+002F</char> is replaced by
                  <code>\"</code>, <code>\b</code>, <code>\f</code>, <code>\n</code>, <code>\r</code>, <code>\t</code>, <phrase>or <code>\/</code></phrase> respectively; </p>
                  </item>

                  <item>
                     <p>any other codepoint in the range 1-31 or 127-159 is replaced by an escape in the form \uHHHH where HHHH 
                  is the upper-case hexadecimal representation of the codepoint value.</p>
                  </item>
               </olist>
            </item>
            <item>
               <p>Otherwise (that is, in the absence of the attribute <code>escaped="true"</code> for a string value, 
            or <code>escaped-key="true"</code> for a key value):</p>

               <olist>
                  <item>
                     <p>any occurrence of backslash is replaced by <code>\\</code></p>
                  </item>

                  <item>
                     <p>any occurrence of 
                        <char>U+0022</char>, <char>U+0008</char>, <char>U+000C</char>, 
                        <char>U+000A</char>, <char>U+000D</char>, or <char>U+0009</char> is 
               replaced by <code>\"</code>, <code>\b</code>, <code>\f</code>, <code>\n</code>, 
                        <code>\r</code>, or <code>\t</code> respectively; </p>
                  </item>

                  <item>
                     <p>any other codepoint in the range 1-31 or 127-159 is replaced by an escape in 
            the form <code>\uHHHH</code> where <code>HHHH</code> is the upper-case hexadecimal representation of the codepoint value.</p>
                  </item>
               </olist>
            </item>
         </olist>

      </fos:rules>
      <fos:errors>

         <p>A dynamic error is raised <errorref spec="FO" class="JS" code="0005"/> if the value of 
            <code>$options</code> includes an entry whose key is defined in this specification, 
            and whose value is not a permitted value for that key.</p>

         <p>A dynamic error is raised <errorref spec="FO" class="JS" code="0006"/> if the value of
            <code>$node</code> is not a document or element node or is not valid according to the schema for the XML representation of
            JSON<phrase>, or if a <code>map</code> element has two children whose normalized key values are the same.</phrase></p>

         <p>A dynamic error is raised <errorref spec="FO" class="JS" code="0007"/> if the value of
            <code>$node</code> includes a string labeled with <code>escaped="true"</code>, or
            a key labeled with <code>escaped-key="true"</code>, where the content of the string or key
            contains an invalid JSON escape sequence: specifically, where it contains a backslash (<code>\</code>) that is not followed by one
            of the characters <code>"</code>, <code>\</code>, <code>/</code>, <code>b</code>, <code>f</code>, <code>n</code>, 
            <code>r</code>, <code>t</code>, or <code>u</code>, or where it contains the characters <code>\u</code>
            not followed by four hexadecimal digits (that is <code>[0-9A-Fa-f]{4}</code>).
        </p>

      </fos:errors>
      <fos:notes>
         <p>The rule requiring schema validity has a number of consequences, including the following:</p>
         <olist>
            <item>
               <p>The input cannot contain no-namespace attributes, or attributes in the namespace <code>http://www.w3.org/2005/xpath-functions</code>,
            except where explicitly allowed by the schema. Attributes in other namespaces, however, are ignored.</p>
            </item>
            <item>
               <p>Nodes that do not affect schema validity, such as comments, processing instructions, namespace nodes, and whitespace text node
            children of <code>map</code> and <code>array</code>, are ignored.</p>
            </item>
            <item>
               <p>Numeric values are restricted to those that are valid in JSON: 
            the schema disallows positive and negative infinity and <code>NaN</code>.</p>
            </item>
            <item>
               <p>Duplicate key values are not permitted. <phrase>Most cases of duplicate keys are prevented by the rules in the schema; 
            additional cases (where the keys are equal only after expanding JSON escape sequences) are prevented by the prose rules 
            of this function. For example, the key values <code>\n</code> and <code>\u000A</code> are treated as duplicates even though
            the rules in the schema do not treat them as such.</phrase></p>
            </item>
         </olist>
         <p>The rule allowing the top-level element to have a <code>key</code> attribute (which is ignored)
         allows any element in the output of the <function>fn:json-to-xml</function> function
         to be processed: for example, it is possible to take a JSON document, convert it to XML, select
         a subtree based on the value of a <code>key</code> attribute, and then convert this subtree
         back to JSON, perhaps after a transformation. The rule means that an element with the appropriate name will be 
            accepted if it has been validated against one of the 
            types <code>mapWithinMapType</code>, <code>arrayWithinMapType</code>, <code>stringWithinMapType</code>, 
            <code>numberWithinMapType</code>, <code>booleanWithinMapType</code>, or <code>nullWithinMapType</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>The input <code><![CDATA[<array xmlns="http://www.w3.org/2005/xpath-functions"><number>1</number><string>is</string><boolean>1</boolean></array>]]></code>
         produces the result <code>[ 1, "is", true ]</code>.</p>
         </fos:example>
         <fos:example>
            <p>The input <code><![CDATA[<map xmlns="http://www.w3.org/2005/xpath-functions"><number key="Sunday">1</number><number key="Monday">2</number></map>]]></code>
            produces the result <code>{ "Sunday": 1, "Monday": 2 }</code>.</p>
         </fos:example>
         <fos:example>
            <p>The input <code><![CDATA[<array xmlns="http://www.w3.org/2005/xpath-functions"><number>10</number><number>17e2</number><number>0005</number></array>]]></code>
            produces the result <code>[ 10, 17e2, 5 ]</code>.</p>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1347" PR="1353" date="2024-09-03"><p>An option has been added to suppress the escaping 
            of the solidus (forwards slash) character.</p></fos:change>
         <fos:change issue="1445" PR="1455" date="2024-10-01"><p>Numbers now retain their original lexical form, except for
         any changes needed to satisfy JSON syntax rules (for example, stripping leading zero digits).</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="element-to-map-plan" prefix="fn">
      <fos:signatures>
         <fos:proto name="element-to-map-plan" return-type="map( xs:string,
     ( fn:element-conversion-plan-record | fn:attribute-conversion-plan-record )
   )  ">
            <fos:arg name="input" type="(document-node() | element())*" usage="absorption"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Analyzes sample data to generate a conversion plan suitable for use by the <function>element-to-map</function>
            function.</p>
      </fos:summary>
      <fos:rules>
         <p>The function takes as input a collection of document and element nodes and analyzes the trees rooted at these
         nodes to determine a conversion plan for converting elements in these trees to maps, suitable for serialization
         in JSON format. The conversion plan can be used <emph>as-is</emph> by supplying it directly to the 
            <function>element-to-map</function> function; alternatively it can be amended before use. The plan can also
         be serialized to a file (in JSON format) allowing the same plan to be used repeatedly for transforming documents
         with a similar structure to those in the sample provided.</p>
         <p>The rules followed by the function, and the detailed format of the conversion plan, are described
         in <specref ref="id-creating-a-conversion-plan"/>.</p>
      </fos:rules>
      <fos:equivalent style="xquery-expression">
let $data-type := fn($nodes as node()*) {
  if (every($nodes ! (. castable as xs:boolean))) then "boolean"
  else if (every($nodes ! (. castable as xs:numeric))) then "numeric"
  else ()
}
let $name := fn($node as node()) {
  if (namespace-uri($node)) 
  then expanded-QName(node-name($node))
  else local-name($node)
}  
return (
  for $ee in $input/descendant-or-self::*
  group by $n := $name($ee)
  return { $n :
           if (empty($ee/(*|text())))
             then { 'layout' : if (empty($ee/@*)) 
                               then 'empty' 
                               else 'empty-plus' } 
           else if (empty($ee/*)) 
             then map:merge((
                    if (empty($ee/@*)) 
                      then {'layout': 'simple'}
                      else {'layout': 'simple-plus'},
                    $data-type($ee) ! { 'type': . }
                 ))
           else if (empty($ee/text()[normalize-space()])) 
             then if (all-equal($ee/*/node-name()) and exists($ee/*[2]))
                    then { 'layout': if (empty($ee/@*)) 
                                     then 'list' 
                                     else 'list-plus',
                           'child': $name(head($ee/*))
                         }
                    else { 'layout' : if (every($ee ! all-different(*/node-name())))
                                      then 'record'
                                      else 'sequence'
                         }             
           else {'layout': 'mixed'}
        },
  for $a in $input//@*
  group by $n := $name($a)
  let $t := $data-type($a)
  return $t ! { `@{$n}`: { 'type': $t } }
) => map:merge()        
      </fos:equivalent>
      <fos:notes>
         <p>The conversion plan is organized by element and attribute name, so its effectiveness depends on the 
         <code>$input</code> collection being homogenous in its structure, and representative of the documents
         that will subsequently be converted using the <function>element-to-map</function> function.</p>
         <p>This function is separate from the <function>element-to-map</function> function for a number
         of reasons:</p>
         <ulist>
            <item><p>The collection of documents that need to be analyzed to establish an effective
            conversion plan might be much smaller than the set of documents actually being converted.</p></item>
            <item><p>Conversely, it might be that only a small number of documents need to be converted at 
            a particular time, but the conversion plan used needs to take into account variations that might
            exist within a larger corpus.</p></item>
            <item><p>If JSON output is required in a particular format, it might be necessary to fine-tune
            the automatically generated conversion plan to take account of these requirements.</p></item>
            <item><p>It might be necessary to devise a conversion plan that can be used to convert individual
            documents as they arrive over a period of time, and to ensure that the same conversion rules
            are applied to each document even though documents might exhibit variations in structure.</p></item>
            <item><p>The conversion plan is human-readable, which can help in understanding why the
            output of <function>element-to-map</function> is in a particular form.</p></item>
         </ulist>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[
element-to-map-plan(<a><b>3</b><b>4</b></a>)
               ]]></eg></fos:expression>
               <fos:result><eg>
{ 'a': { 'layout': 'list', 'child': 'b' },
  'b': { 'layout': 'simple', 'type': 'numeric' }
}
               </eg></fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[
element-to-map-plan((<a x="2">red</a>, <a x="3">blue</a>))
               ]]></eg></fos:expression>
               <fos:result><eg>
{ 'a': { 'layout': 'simple-plus' },
  '@x': { 'type': 'numeric' }
}
               </eg></fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[
element-to-map-plan(
   <a xmlns="http://example.ns">H<sub>2</sub>SO<sub>4</sub></a>
)
               ]]></eg></fos:expression>
               <fos:result><eg>
{ 'Q{http://example.ns}a': { 'layout': 'mixed' },
  'Q{http://example.ns}sub': { 'layout': 'simple', 'type': 'numeric' }
}
               </eg></fos:result>
            </fos:test>   
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[
element-to-map-plan((<a><b/><b/></a>, <a><b/><c/></a>))
               ]]></eg></fos:expression>
               <fos:result><eg>
{ 'a': { 'layout': 'sequence' },
  'b': { 'layout': 'empty' },
  'c': { 'layout': 'empty' }
}
               </eg></fos:result>
            </fos:test>   
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1797" PR="1906" date="2025-04-29"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
      
   <fos:function name="element-to-map" prefix="fn">
      <fos:signatures>
         <fos:proto name="element-to-map" return-type="map(xs:string, item()?)?">
            <fos:arg name="element" type="element()?" usage="absorption"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Converts an element node into a map that is suitable for
            JSON serialization.</p>
      </fos:summary>
      <fos:rules>
         <p>This function returns a map derived from
            the element node supplied in <code>$element</code>. The map is in a form
            that is suitable for JSON serialization, thus providing a mechanism for conversion
            of arbitrary XML to JSON.</p>
         
         <p>The map that is returned will always be a <termref def="dt-single-entry-map"/>;
         the key of this entry will be a string representing the element name, and the value of the
         entry will be a representation of the element's attributes and children.</p>
         
         
         <p>The entries that may appear in the <code>$options</code> map are as follows.
         The <termref def="option-parameter-conventions">option parameter conventions</termref> apply.</p>
         
         <fos:options>
            
            <fos:option key="plan">
               <fos:meaning>A conversion plan, supplied as a map whose keys represent element
                  and attribute names. The plan might be generated using the function
                  <function>element-to-map-plan</function>, or it might be constructed
                  in some other way. The format of the plan is described in <specref ref="id-creating-a-conversion-plan"/>.
               </fos:meaning>
               <fos:type>map( xs:string,
     ( fn:element-conversion-plan-record | fn:attribute-conversion-plan-record )
   )  </fos:type>
               <fos:default>{}</fos:default>
            </fos:option>
            <fos:option key="attribute-marker">
               <fos:meaning>A string that is prepended to any key value in the output that represents
               an XDM attribute node in the input. The string may be empty. If, after applying the requested
               prefix (or no prefix) there is a conflict between the names of attributes and child elements,
               then the requested prefix (or lack thereof) is ignored and the default prefix <code>"@"</code>
               is used.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"@"</fos:default>
            </fos:option>
            <fos:option key="name-format">
               <fos:meaning>Indicates how the names of element and attribute nodes are handled.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"default"</fos:default>
               <fos:values>
                  <fos:value value="lexical">Names are output in the form produced by the <function>fn:name</function> function.</fos:value>
                  <fos:value value="local">Names are output in the form produced by the <function>fn:local-name</function> function.</fos:value>
                  <fos:value value="eqname">Names in a namespace are output in the form <code>"Q{uri}local"</code>.
                  Names in no namespace are output using the local name alone.</fos:value>
                  <fos:value value="default">An element name is output as a local name alone if either (a) it is
                     a top-level element and is in no namespace, or (b) it is in the same namespace as its
                     parent element. An attribute name is output as a local name alone if it is in no namespace.
                     All other names are output in the format <code>"Q{uri}local"</code> if in a namespace, 
                     or <code>"Q{}local"</code> if in no namespace. "Top-level" here means that the element
                     is one that appears explicitly in the sequence of elements passed in the <code>$elements</code> argument,
                     as distinct from a descendant of such an element.</fos:value>
               </fos:values>
            </fos:option>
         </fos:options>
         
         
         <p>If <code>$element</code> is the empty sequence, the result is the empty sequence.</p>
         
         
         <p>The principles for conversion from elements to maps are described
            in <specref ref="id-element-layouts"/>, and the rules for selecting
         an element layout for each element are given in 
            <specref ref="id-selecting-element-layout"/>.</p>
         
        
         <p>In general, every descendant element within the tree rooted at the supplied
            <code>$element</code> maps to a key-value pair in which the key represents the element name, and the
         corresponding value represents the attributes and children of the element. This key-value pair will be added 
         to the content representing its parent element, in a way that depends on the parent element's layout.</p>
         
         <p>The representation of a node of any other kind depends on the layout chosen for its parent element.</p>
         
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error <errorref class="JS" code="0008"/> occurs if any element cannot
            be processed using the selected layout for that element, unless fallback processing
            is defined; or if error action is explicitly requested for an element.</p>
         <p>Any error in the conversion plan is treated as a type error <xerrorref
               spec="XP" class="TY" code="0004"/> whether or not it is technically
            a contravention of the defined type for the value. This relieves users and implementers
            of the burden of distinguishing different kinds of error in the plan.</p>
 
      </fos:errors>
 
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>element-to-map(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><![CDATA[element-to-map(<foo>bar</foo>)]]></fos:expression>
               <fos:result>{ "foo": "bar" }</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[element-to-map(
    <list>
      <item value='1'/>
      <item value='2'/>
    </list>, { 'attribute-marker': '' }
  )]]></eg></fos:expression>
               <fos:result><eg>{ "list": [ 
    { "value": "1" },
    { "value": "2" }
  ] }</eg></fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[element-to-map(
    <name>
      <first>Jane</first>
      <last>Smith</last>
    </name>
  )]]></eg></fos:expression>
               <fos:result><eg>{ "name": { 
  "first": "Jane",
  "last": "Smith" 
} }</eg></fos:result>
            </fos:test>
           <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[element-to-map(
    <name xmlns="http://example.ns/">
      <first>Jane</first>
      <middle>Elizabeth</middle>
      <middle>Mary</middle>
      <last>Smith</last>
    </name>, 
    { 'plan': {'Q{http://example.ns/}name': { 'layout': 'record' }},
      'name-format' : 'local'
    }
  )]]></eg></fos:expression>
               <fos:result><eg>{ "name": { 
    "first": "Jane",
    "middle": ["Elizabeth", "Mary"],
    "last": "Smith" 
  } 
}</eg></fos:result>
            </fos:test>            
 <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[element-to-map(
    <name xmlns="http://example.ns/">
      <first>Jane</first>
      <middle>Elizabeth</middle>
      <middle>Mary</middle>
      <last>Smith</last>
    </name>, 
    { 'plan': {'Q{http://example.ns/}name': { 'layout': 'record' },
               'Q{http://example.ns/}middle': { 'layout': 'deep-skip' }
              },
      'name-format' : 'local'
    }
  )]]></eg></fos:expression>
               <fos:result><eg>{ "name": { 
    "first": "Jane",
    "last": "Smith" 
  } 
}</eg></fos:result>
            </fos:test> 
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1797" PR="1906" date="2025-04-29"><p>New in 4.0.</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="parse-csv" prefix="fn">
      <fos:signatures>
         <fos:proto name="parse-csv" return-type-ref="parsed-csv-structure-record" return-type-ref-occurs="?">
            <fos:arg name="value" type="xs:string?" example="'&lt;a/&gt;'"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Parses CSV data, returning the results in the form of a record containing information about the
            names in the header, as well as the data itself.</p>
      </fos:summary>
      <fos:rules>

         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>

         <p>The input supplied in <code>$value</code> is CSV data, as defined
            in <bibref ref="rfc4180"/>. The function
            first parses the input using <function>fn:csv-to-arrays</function>, and then
            further processes the result. The initial parsing is exactly as defined for
            <function>fn:csv-to-arrays</function>, and can be controlled using the same options.
            Additional options are available to control the way in which header information and
            column names are handled.</p>

         <p>If the input is the a zero-length string, the function
               returns a <code>parsed-csv-structure-record</code> whose 
               <code>rows</code> entry is the empty sequence.</p>
         
         <p>The <code>$options</code> argument can be used to control the way in which the parsing
            takes place. The <termref
               def="option-parameter-conventions">option parameter conventions</termref> apply.</p>
         
         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>
         <fos:options>
            <fos:option key="field-delimiter">
               <fos:meaning>The character used to delimit fields within a record. An instance of
                  <code>xs:string</code> whose length is exactly one.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>","</fos:default>
            </fos:option>
            <fos:option key="row-delimiter">
               <fos:meaning>The character used to delimit rows within
                  the CSV string. An instance of
                  <code>xs:string</code> whose length is exactly one.
                  Defaults to a single newline character (<char>U+000A</char>).
                  Note that this is tested after line endings are normalized.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>char('\n')</fos:default>
            </fos:option>
            <fos:option key="quote-character">
               <fos:meaning>The character used to quote fields within the CSV string. An instance of
                  <code>xs:string</code> whose length is exactly one.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>'"'</fos:default>
            </fos:option>
            <fos:option key="trim-whitespace">
               <fos:meaning>Determines whether leading and trailing whitespace
                  is removed from the content of unquoted fields.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">Unquoted fields will be returned with any leading or trailing
                     whitespace intact.
                  </fos:value>
                  <fos:value value="true">Unquoted fields will be returned with leading or trailing
                     whitespace removed, and all other whitespace preserved.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="header">
               <fos:meaning>Determines whether the first row of the CSV should be treated as a list
                  of column names, or whether column names are being supplied by the caller. 
                  The value must either be a single boolean, or a sequence of zero or more strings.
               </fos:meaning>
               <fos:type>item()*</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="true">Column names are taken from the
                     first row of the CSV data.</fos:value>
                  <fos:value value="false">Column names are not available; all references
                     to columns are by ordinal position.</fos:value>
                  <fos:value value="xs:string*">Supplies explicit names for the columns. The <var>N</var>th
                     name in the list applies to the <var>N</var>th column after any filtering or rearrangement.
                     A zero-length string can be used when there is a column that requires no name.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="select-columns">
               <fos:meaning>A sequence of integers indicating which columns to include and in which order. If this
                  option is absent or empty, all columns are returned in their original
                  order. For example, the value <code>1 to 4</code> indicates that the output
                  contains the first, second, third, and fourth columns from the input, in order,
                  while <code>(1, 5, 4)</code> indicates that the output
                  contains three columns, taken from the first, fifth, and fourth columns of the input,
                  in that order. An integer in the sequence is treated as the 1-based 
                  index of the column to include. Any other columns are dropped. 
                  If a particular row includes no field at the specified index,
                  the empty field is included at the relevant position in the result. If an integer appears
                  more than once then the result will include duplicated columns.
               </fos:meaning>
               <fos:type>xs:positiveInteger*</fos:type>
               <fos:default>()</fos:default>
            </fos:option>
            <fos:option key="trim-rows">
               <fos:meaning>Determines whether all rows should be adjusted to
                  contain the same number of fields. This option is ignored if
                  <code>select-columns</code> is specified.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">No padding or trimming of rows takes place,
                  unless requested using the <code>select-columns</code> option.</fos:value>
                  <fos:value value="true">The number of fields in the first row (whether this
                     be a header or a data row) determines the number of fields in every
                     subsequent row; to achieve this, excess fields are removed, or
                     additional zero-length fields are added.
                  </fos:value>
               </fos:values>
            </fos:option>
         </fos:options>

         <p>The result of the function is a <code>parsed-csv-structure-record</code>, as
         defined in <specref ref="parsed-csv-structure-record"/>.</p>
         


      </fos:rules>
      <fos:errors>
         <p>A dynamic error <errorref class="CV" code="0001"/> occurs if the value of
            <code>$csv</code> does not conform to the required grammar.</p>
         <p>A dynamic error <errorref class="CV" code="0002"/> occurs if any of the
            options <code>field-delimiter</code>, <code>row-delimiter</code>, or <code>quote-character</code>
            is not a single character.</p>
         <p>A dynamic error <errorref class="CV" code="0003"/> occurs if the same character is used
            for more than one of the options
            <code>field-delimiter</code>, <code>row-delimiter</code>, and
            <code>quote-character</code>.</p>

      </fos:errors>
      <fos:notes>
         <p>The default row delimiter is a single newline character <char>U+000A</char>. 
            Alternative line endings
         such as <code>CR</code> and <code>CRLF</code> will already have been normalized to a single
         newline.</p>
         <p>All fields are returned as <code>xs:string</code> values.</p>
         <p>Quoted fields in the input are returned without the quotes.</p>
         <p>For more discussion of the returned data, see <specref ref="csv-to-xdm-mapping"/>.</p>
         <p>If the source of the CSV input is a resource accessible by URI, then it may be preferable
         to use the <function>fn:csv-doc</function> function. If the source is a binary value (<code>xs:hexBinary</code>
         or <code>xs:base64Binary</code>) then this can first be decoded as a string using the functions
         <function>bin:infer-encoding</function> and <function>bin:decode-string</function>.</p>
      </fos:notes>
      <fos:examples>
         <fos:variable name="display" id="csv-display">fn($result) {
  (: tidy up the result for display (function items cannot be properly displayed) :)         
  map:put($result, "get", "(: function :)")
}</fos:variable>

         <fos:example>
            <p>Default delimiters, no column headers:</p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $input := string-join(
  ("name,city", "Bob,Berlin", "Alice,Aachen"),
  char('\n')
)
let $result := parse-csv($input)
return (
  $result => $display(),
  $result?get(1, 2),
  $result?get(2, 2)
)</eg></fos:expression>
               <fos:result><eg>{
  "columns": (),
  "column-index": {},
  "rows": ([ "name", "city" ], [ "Bob", "Berlin" ], [ "Alice", "Aachen" ]),
  "get": "(: function :)"
},
"city",
"Berlin"</eg></fos:result>
            </fos:test>

            <p>Default delimiters, column headers:</p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $input := string-join(
  ("name,city", "Bob,Berlin", "Alice,Aachen"),
  char('\n')
)
let $result := parse-csv($input, { "header": true() })
return (
  $result => $display(),
  $result?get(1, "name"),
  $result?get(2, "city")
)</eg></fos:expression>
<fos:result><eg>{
  "columns": ("name", "city"),
  "column-index": { "name": 1, "city": 2 },
  "rows": ([ "Bob", "Berlin" ], [ "Alice", "Aachen" ]),
  "get": "(: function :)"
},
"Bob",
"Aachen"</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Custom delimiters, no column headers:</p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $options := {
  "row-delimiter": "§", 
  "field-delimiter": ";", 
  "quote-character": "|"
}
let $input := "|name|;|city|§|Bob|;|Berlin|§|Alice|;|Aachen|"
let $result := parse-csv($input, $options)
return (
  $result => $display(),
  $result?get(3, 1)
)</eg></fos:expression>
               <fos:result><eg>{
  "columns": (),
  "column-index": {},
  "rows": ([ "name", "city" ], [ "Bob", "Berlin" ], [ "Alice", "Aachen" ]),
  "get": "(: function :)"
},
"Alice"</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Supplied column names:</p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $headers := ("Person", "Location")
let $options := { "header": $headers, "row-delimiter": ";" }
let $input := "Alice,Aachen;Bob,Berlin;"
let $parsed-csv := parse-csv($input, $options)
return (
  $parsed-csv => $display(), 
  $parsed-csv?get(2, "Location")
)</eg></fos:expression>
               <fos:result><eg>{
  "columns": ("Person", "Location"),
  "column-index": { "Person": 1, "Location": 2 },
  "rows": ([ "Alice", "Aachen" ], [ "Bob", "Berlin" ]),
  "get": "(: function :)"                  
},
"Berlin"</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Filtering columns, with ragged input and <code>header: true()</code></p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $input := string-join((
   "date,name,city,amount,currency,original amount,note",
   "2023-07-19,Bob,Berlin,10.00,USD,13.99",
   "2023-07-20,Alice,Aachen,15.00",
   "2023-07-20,Charlie,Celle,15.00,GBP,11.99,cake,not a lie"
), char('\n'))
let $options := { 
  "header": true(), 
  "select-columns": (2, 1, 4)
}
let $result := parse-csv($input, $options)
return (
  $result => $display(),
  $result?get(2, "amount")
)</eg></fos:expression>
               <fos:result><eg>{
  "columns": ("name", "date", "amount"),
  "column-index": { "name": 1, "date": 2, "amount": 3 },
  "rows": (
    [ "Bob", "2023-07-19", "10.00" ],
    [ "Alice", "2023-07-20", "15.00" ],
    [ "Charlie", "2023-07-20", "15.00" ]
  ),
  "get": "(: function :)"                  
},
"15.00"</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Filtering columns, with supplied column map</p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $input := string-join((
  "2023-07-20,Alice,Aachen,15.00",                  
  "2023-07-19,Bob,Berlin,10.00,USD,13.99",
  "2023-07-20,Charlie,Celle,15.00,GBP,11.99,cake,not a lie"
), char('\n'))
let $options := { 
  "header": ( "Person", "", "Amount" ),
  "select-columns": (2, 1, 4)
}
let $result := parse-csv($input, $options)
return (
  $result => $display(),
  $result?get(2, "Person"),
  $result?get(2, "Amount")
)</eg></fos:expression>
               
               <fos:result><eg>{
  "columns": ("Person", "", "Amount"),
  "column-index": { "Person": 1, "Amount": 3 },
  "rows": ([ "Alice", "2023-07-20", "15.00" ], 
           [ "Bob", "2023-07-19", "10.00" ], 
           [ "Charlie", "2023-07-20", "15.00" ]),
  "get": "(: function :)"                  
},
"Bob",
"10.00"</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Specifying the number of columns explicitly, with <code>header: false()</code></p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $input := string-join((
  "date,      name,     amount,    currency,   original amount",               
  "2023-07-19,Bob,      10.00,     USD,        13.99",
  "2023-07-20,Alice,    15.00",
  "2023-07-20,Charlie,  15.00,     GBP,        11.99,             extra data"
), char('\n'))
let $options := {
  "header": false(), 
  "select-columns": 1 to 5, 
  "trim-whitespace" :true()
}
let $result := parse-csv($input, $options)
return (
  $result => $display(),
  $result?get(4, 3)
)</eg></fos:expression>
               <fos:result><eg>{
  "columns": (),
  "column-index": {},
  "rows": (
    [ "date", "name", "amount", "currency", "original amount" ],
    [ "2023-07-19", "Bob", "10.00", "USD", "13.99" ],
    [ "2023-07-20", "Alice", "15.00", "", "" ],
    [ "2023-07-20", "Charlie", "15.00", "GBP", "11.99" ]
  ),
  "get": "(: function :)"                  
},
"15.00"</eg></fos:result>
               
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Specifying the number of columns with a number and <code>header: true()</code></p>
            <fos:test use="csv-display">
               <fos:expression><eg>let $input := string-join((
  "date,name,city,amount,currency,original amount,note",               
  "2023-07-19,Bob,Berlin,10.00,USD,13.99",
  "2023-07-20,Alice,Aachen,15.00",
  "2023-07-20,Charlie,Celle,15.00,GBP,11.99,cake,not a lie"
), char('\n'))
let $options := { "header": true(), "select-columns": 1 to 6 }
let $result := parse-csv($input, $options)
return (
  $result => $display(),
  $result?get(3, "original amount")
)</eg></fos:expression>
               <fos:result><eg>{
  "columns": ("date", "name", "city", 
              "amount", "currency", "original amount"),
  "column-index": {
    "date": 1, "name": 2, "city": 3, "amount": 4,
    "currency": 5, "original amount": 6
  },
  "rows": (
    [ "2023-07-19", "Bob", "Berlin", "10.00", "USD", "13.99"],
    [ "2023-07-20", "Alice", "Aachen", "15.00", "", ""],
    [ "2023-07-20", "Charlie", "Celle", "15.00", "GBP", "11.99"]
  ),
  "get": "(: function :)"                  
},
"11.99"</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change PR="533 719 834 1066" issue="413 1052" date="2024-03-19"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="csv-doc" prefix="fn">
      <fos:signatures>
         <fos:proto name="csv-doc" return-type="fn:parsed-csv-structure-record?">
            <fos:arg name="source" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Reads an external resource containing CSV, and returns the results as a record
            containing information about the names in the header, as well as the data itself.</p>
      </fos:summary>
      <fos:rules>
         <p>The effect of the two-argument function call <code>fn:csv-doc($H, $M)</code> is
            equivalent to the function composition
            <code>fn:unparsed-binary($H) => fn:parse-csv($M)</code>.</p>
         <p>If <code>$source</code> is the empty sequence, the function returns the empty sequence.</p>
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
      </fos:rules>
      <fos:errors>
         <p>The function may raise any error defined for the <function>fn:unparsed-text</function>
         or <function>fn:parse-csv</function> functions.</p>
      </fos:errors>
      <fos:changes>
         <fos:change issue="748" PR="2013" date="2025-05-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="csv-to-arrays" prefix="fn">
      <fos:signatures>
         <fos:proto name="csv-to-arrays" return-type="array(xs:string)*">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Parses CSV data supplied as a string, returning the results in the form of a sequence
            of arrays of strings.</p>
      </fos:summary>
      <fos:rules>
         
         <p>The <code>$value</code> argument is CSV data, as defined in <bibref ref="rfc4180"/>, in the form of an
            <code>xs:string</code> value. The function parses this string,
            after normalizing newlines so that <char>U+000D</char> and (<char>U+000D</char>, <char>U+000A</char>)
            sequences are converted to <char>U+000A</char>.
            The result of the function is a sequence of arrays of strings, that is
            <code>array(xs:string)*</code>; each array represents one row of the CSV input.</p>
         
         <p>If <code>$value</code> is the empty sequence or a zero-length string, the 
            function returns the empty sequence.</p>
         
         <p>The <code>$options</code> argument can be used to control the way in which the parsing
            takes place. The <termref
               def="option-parameter-conventions">option parameter conventions</termref> apply.</p>

         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>

         <fos:options>
            <fos:option key="field-delimiter">
               <fos:meaning>The character used to delimit fields within a record. An instance of
                  <code>xs:string</code> whose length is exactly one.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>","</fos:default>
            </fos:option>
            <fos:option key="row-delimiter">
               <fos:meaning>The character used to delimit rows within
                  the CSV string. An instance of
                  <code>xs:string</code> whose length is exactly one.
                  Defaults to a single newline character (<char>U+000A</char>).</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>char('\n')</fos:default>
            </fos:option>
            <fos:option key="quote-character">
               <fos:meaning>The character used to quote fields within the CSV string. An instance of
                  <code>xs:string</code> whose length is exactly one.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>'"'</fos:default>
            </fos:option>
            <fos:option key="trim-whitespace">
               <fos:meaning>Determines whether leading and trailing whitespace
                  is removed from the content of unquoted fields.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">Unquoted fields will be returned with any leading or trailing
                     whitespace intact.
                  </fos:value>
                  <fos:value value="true">Unquoted fields will be returned with leading or trailing
                     whitespace removed, and all other whitespace preserved.
                  </fos:value>
               </fos:values>
            </fos:option>
            <!--<fos:option key="normalize-newlines">
               <fos:meaning>Determines whether CR and CRLF character sequences
                  are treated as equivalent to NL characters.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false()</fos:default>
               <fos:values>
                  <fos:value value="false">No normalization takes place.
                  </fos:value>
                  <fos:value value="true">The character sequences CR (<char>U+000D</char>)
                     and CRLF (<char>U+000D</char>, <char>U+000A</char>) are treated as equivalent to the
                     character NL (<char>U+000A</char>), except when they appear within a quoted field. 
                     The normalization is done prior to recognition of row delimiters, and happens
                     whether or not NL is used as the row delimiter.
                  </fos:value>
               </fos:values>
            </fos:option>-->
         </fos:options>

         <p>An empty field is represented by a zero-length string. An empty field is deemed to exist
         when a field delimiter immediately follows either another field delimiter, or
         a row delimiter, or the start of <code>$value</code>; or when a row delimiter or the
         end of <code>$value</code> immediately follows a field delimiter.</p>
         
         <p>A blank row is represented as the empty array (not as an
            array containing a single empty field). A blank row is deemed to exist when a
            row delimiter immediately follows either another row delimiter or the start of <code>$value</code>,
         after trimming of whitespace if the <code>trim-whitespace</code> option is <code>true</code>.
         No blank row occurs after the final row delimiter.</p>
         
         <p>If <code>$value</code> is a zero-length string, the CSV is considered to
         contain no rows; while if <code>$value</code> consists of a single row delimiter,
         it is considered to contain a single blank row. The presence or
         absence of a final row delimiter generally has no effect on the result,
         except when it appears at the start of the input, in which case it causes a
         single blank row to exist.</p>
         
         
      </fos:rules>
      <fos:errors>
         <p>A dynamic error <errorref class="CV" code="0001"/> occurs if the value of
            <code>$csv</code> does not conform to the required grammar.</p>
         <p>A dynamic error <errorref class="CV" code="0002"/> occurs if the value of the
            <code>field-delimiter</code>, <code>row-delimiter</code>, or 
            <code>quote-character</code> option is not a single character.</p>
         <p>A dynamic error <errorref class="CV" code="0003"/> occurs if the same character
            is used for more than one of the
            <code>field-delimiter</code>, <code>row-delimiter</code>, and
            <code>quote-character</code>.</p>
      </fos:errors>
      <fos:notes>
         <p>The default row delimiter is a single newline character <char>U+000A</char>. 
            Alternative line endings
            such as <code>CR</code> and <code>CRLF</code> will already have been normalized to a single
            newline. </p>
         <p>All fields are returned as <code>xs:string</code> values.</p>
         <p>Quoted fields in the input are returned without the quotes.</p>
         <p>The first row is not treated specially.</p>
         <p>For more discussion of the returned data, see <specref ref="basic-csv-to-xdm-mapping"/>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>Handling trivial input:</p>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(())</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays("")</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(char('\n'))</eg></fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(" ", { 'trim-whitespace': true() })</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(" ", { 'trim-whitespace': false() })</eg></fos:expression>
               <fos:result>[ " " ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(` { char('\n') }`, { 'trim-whitespace': true() })</eg></fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(` { char('\n') }`, { 'trim-whitespace': false() })</eg></fos:expression>
               <fos:result>[ " " ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(`{ char('\n') } `, { 'trim-whitespace': true() })</eg></fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(`{ char('\n') } `, { 'trim-whitespace': false() })</eg></fos:expression>
               <fos:result>[], [ " " ]</fos:result>
            </fos:test>
            <p>Using newline separators:</p>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(
  `name,city{ char('\n') }` ||
  `Bob,Berlin{ char('\n') }` ||
  `Alice,Aachen{ char('\n') }`
)</eg></fos:expression>
               <fos:result><eg>[ "name", "city" ],
[ "Bob", "Berlin" ],
[ "Alice", "Aachen" ]</eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>let $CRLF := `{ char('\r') }{ char('\n') }`
return csv-to-arrays(
  `name,city{ $CRLF }` ||
  `Bob,Berlin{ $CRLF }` ||
  `Alice,Aachen{ $CRLF }`
)</eg></fos:expression>
               <fos:result><eg>[ "name", "city" ],
[ "Bob", "Berlin" ],
[ "Alice", "Aachen" ]</eg></fos:result>
            </fos:test>

         </fos:example>
         <fos:example>
            <p>Quote handling:</p>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(
  string-join(
    (`"name","city"`, `"Bob","Berlin"`, `"Alice","Aachen"`),
    char('\n')
  )
)</eg></fos:expression>
               <fos:result><eg>[ "name", "city" ],
[ "Bob", "Berlin" ],
[ "Alice", "Aachen" ]</eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(
  `"name","city"{ char('\n') }` ||
  `"Bob ""The Exemplar"" Mustermann","Berlin"{ char('\n') }`
)</eg></fos:expression>
               <fos:result><eg>(
  [ "name", "city" ],
  [ 'Bob "The Exemplar" Mustermann', "Berlin" ]
)</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Non-default record- and field-delimiters:</p>
            <fos:test>
               <fos:expression><eg>csv-to-arrays(
  "name;city§Bob;Berlin§Alice;Aachen", 
  { "row-delimiter": "§", "field-delimiter": ";" }
)</eg></fos:expression>
               <fos:result><eg>[ "name", "city" ],
[ "Bob", "Berlin" ],
[ "Alice", "Aachen" ]</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Non-default quote character:</p>
            <fos:test use="escaped-crlf-3">
               <fos:expression><eg>csv-to-arrays(
  string-join(
    ("|name|,|city|", "|Bob|,|Berlin|"),
    char('\n')
  ), 
  { "quote-character": "|" }
)</eg></fos:expression>
               <fos:result><eg>[ "name", "city" ],
[ "Bob", "Berlin" ]</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Trimming whitespace in fields:</p>
            <fos:test use="escaped-crlf-3">
               <fos:expression><eg>csv-to-arrays(
  string-join(
    ("name  ,city    ", "Bob   ,Berlin  ", "Alice ,Aachen  "),
    char('\n')
  ),
  { "trim-whitespace": true() }
)</eg></fos:expression>
               <fos:result><eg>[ "name", "city" ],
[ "Bob", "Berlin" ],
[ "Alice", "Aachen" ]</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change PR="533 719 834 1066" issue="413 1052" date="2023-07-25"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="csv-to-xml" prefix="fn">
      <fos:signatures>
         <fos:proto name="csv-to-xml" return-type="document-node(fn:csv)?">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Parses CSV data supplied as a string, returning the results as an XML document, as described by
            <specref ref="csv-represent-as-xml"/>.</p>
      </fos:summary>
      <fos:rules>
         <p>The arguments have the same meaning, and are subject to the same constraints, as
         the arguments of <function>fn:parse-csv</function>.</p>
         
         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>
         
         <p>In other cases, the effect of the function is equivalent to the result of the 
            following XQuery expression
            (where <code>$options</code> is the empty map if the argument is not supplied):</p>
         
         <eg><![CDATA[let $parsedCSV := parse-csv($value, $options)
let $colNames := $parsedCSV?columns
return document {
   <csv xmlns="http://www.w3.org/2005/xpath-functions"> {
     if (exists($colNames)) {
       <columns>{ $colNames ! <column>{ . }</column> }</columns>
     },
     <rows>{
       for $row in $parsedCSV?rows
       return <row>{
         for member $field at $col in $row
         return <field>{
           if ($colnames[$col]) {
             attribute column { $colnames[$col] }
           },
           $field
         }</field>
       }</row>
     }</rows> 
   }</csv> 
}]]></eg>
         
         <p>The elements in the returned XML are in the namespace
            <code>http://www.w3.org/2005/xpath-functions</code>;
            the namespace prefix that is used (or its absence) is 
            <termref def="implementation-dependent"/>.</p>
         
         <p>If the function is called twice with the same arguments, it is <termref
            def="implementation-dependent"/> whether the two calls return the same element node
            or distinct (but deep equal) element nodes. In this respect it is <termref
               def="dt-nondeterministic">nondeterministic with respect to node identity</termref>.</p>
         
         <p>The base URI of the element nodes in the result is <termref
            def="implementation-dependent"/>.</p>
         
         <p>A schema is defined for the structure of the returned document: see <specref
            ref="schema-for-csv"/>.</p>
         
         <p>The result of the function will always be such that validation against this schema would succeed.
            However, it is <termref
               def="implementation-defined"/> whether the result is typed or untyped,
            that is, whether the elements and attributes in the returned tree have type annotations that reflect
            the result of validating against this schema.</p>
         
         
 
      </fos:rules>
      <fos:errors>
         <p>See <function>fn:parse-csv</function>.</p>
      </fos:errors>
      <fos:examples>
         <fos:variable name="crlf" id="escaped-crlf-3"><![CDATA[char('\r') || char('\n')]]></fos:variable>
         <fos:variable name="csv-string" id="csv-string-2">`name,city{ $crlf }Bob,Berlin{ $crlf }Alice,Aachen{ $crlf }`</fos:variable>
         <fos:example>
            <p>An empty CSV with default column extraction (false):</p>
            <fos:test>
               <fos:expression><eg>csv-to-xml(())</eg></fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-xml("")</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <rows/>
</csv>
]]></eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>csv-to-xml(char('\n'))</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <rows>
    <row/>
  </rows>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>An empty CSV with header extraction:</p>
            <fos:test>
               <fos:expression><eg>csv-to-xml("", { "header": true() })</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <rows/>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>An empty CSV with explicit column names:</p>
            <fos:test>
               <fos:expression><eg>csv-to-xml("", { "header": ("name", "", "city") })</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <columns>
    <column>name</column>
    <column/>
    <column>city</column>
  </columns>
  <rows/>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>With defaults for delimiters and quotes, recognizing headers:</p>
            <fos:test use="escaped-crlf-3 csv-string-2">
               <fos:expression><eg>csv-to-xml($csv-string, { "header": true() })</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <columns>
    <column>name</column>
    <column>city</column>
  </columns>
  <rows>
    <row>
      <field column="name">Bob</field>
      <field column="city">Berlin</field>
    </row>
    <row>
      <field column="name">Alice</field>
      <field column="city">Aachen</field>
    </row>
  </rows>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:variable name="csv-uneven-cols" id="uneven-cols-csv-string-2">concat(
  `date,name,city,amount,currency,original amount,note{ $crlf }`,
  `2023-07-19,Bob,Berlin,10.00,USD,13.99{ $crlf }`,
  `2023-07-20,Alice,Aachen,15.00{ $crlf }`,
  `2023-07-20,Charlie,Celle,15.00,GBP,11.99,cake,not a lie{ $crlf }`
)</fos:variable>
         <fos:example>
            <p>Filtering columns</p>
            <fos:test use="escaped-crlf-3 uneven-cols-csv-string-2">
               <fos:expression><eg>csv-to-xml(
  $csv-uneven-cols, 
  { "header": true(), "select-columns": (2, 1, 4) }
)</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <columns>
    <column>name</column>
    <column>date</column>
    <column>amount</column>
  </columns>
  <rows>
    <row>
      <field column="name">Bob</field>
      <field column="date">2023-07-19</field>
      <field column="amount">10.00</field>
    </row>
    <row>
      <field column="name">Alice</field>
      <field column="date">2023-07-20</field>
      <field column="amount">15.00</field>
    </row>
    <row>
      <field column="name">Charlie</field>
      <field column="date">2023-07-20</field>
      <field column="amount">15.00</field>
    </row>
  </rows>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Ragged rows</p>
            <fos:test use="escaped-crlf-3 uneven-cols-csv-string-2">
               <fos:expression><eg>csv-to-xml(
  $csv-uneven-cols, 
  { "header": true() }
)</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <columns>
    <column>date</column>
    <column>name</column>
    <column>city</column>
    <column>amount</column>
    <column>currency</column>
    <column>original amount</column>
    <column>note</column>
  </columns>
  <rows>
    <row>
      <field column="date">2023-07-19</field>
      <field column="name">Bob</field>
      <field column="city">Berlin</field>
      <field column="amount">10.00</field>
      <field column="currency">USD</field>
      <field column="original amount">13.99</field>
    </row>
    <row>
      <field column="date">2023-07-20</field>
      <field column="name">Alice</field>
      <field column="city">Aachen</field>
      <field column="amount">15.00</field>
    </row>
    <row>
      <field column="date">2023-07-20</field>
      <field column="name">Charlie</field>
      <field column="city">Celle</field>
      <field column="amount">15.00</field>
      <field column="currency">GBP</field>
      <field column="original amount">11.99</field>
      <field column="note">cake</field>
      <field>not a lie</field>
    </row>
  </rows>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Trimming rows to constant width</p>
            <fos:test use="escaped-crlf-3 uneven-cols-csv-string-2">
               <fos:expression><eg>csv-to-xml(
  $csv-uneven-cols, 
  { "header": true(), "trim-rows": true() }
)</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <columns>
    <column>date</column>
    <column>name</column>
    <column>city</column>
    <column>amount</column>
    <column>currency</column>
    <column>original amount</column>
    <column>note</column>
  </columns>
  <rows>
    <row>
      <field column="date">2023-07-19</field>
      <field column="name">Bob</field>
      <field column="city">Berlin</field>
      <field column="amount">10.00</field>
      <field column="currency">USD</field>
      <field column="original amount">13.99</field>
      <field column="note"/>
    </row>
    <row>
      <field column="date">2023-07-20</field>
      <field column="name">Alice</field>
      <field column="city">Aachen</field>
      <field column="amount">15.00</field>
      <field column="currency"/>
      <field column="original amount"/>
      <field column="note"/>
    </row>
    <row>
      <field column="date">2023-07-20</field>
      <field column="name">Charlie</field>
      <field column="city">Celle</field>
      <field column="amount">15.00</field>
      <field column="currency">GBP</field>
      <field column="original amount">11.99</field>
      <field column="note">cake</field>
    </row>
  </rows>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <p>Specifying a fixed number of columns</p>
            <fos:test use="escaped-crlf-3 uneven-cols-csv-string-2">
               <fos:expression><eg>csv-to-xml(
  $csv-uneven-cols, 
  { "header": true(), "select-columns": 1 to 6 }
)</eg></fos:expression>
               <fos:result normalize-space="true"><eg><![CDATA[
<csv xmlns="http://www.w3.org/2005/xpath-functions">
  <columns>
    <column>date</column>
    <column>name</column>
    <column>city</column>
    <column>amount</column>
    <column>currency</column>
    <column>original amount</column>
  </columns>
  <rows>
    <row>
      <field column="date">2023-07-19</field>
      <field column="name">Bob</field>
      <field column="city">Berlin</field>
      <field column="amount">10.00</field>
      <field column="currency">USD</field>
      <field column="original amount">13.99</field>
    </row>
    <row>
      <field column="date">2023-07-20</field>
      <field column="name">Alice</field>
      <field column="city">Aachen</field>
      <field column="amount">15.00</field>
      <field column="currency"/>
      <field column="original amount"/>
    </row>
    <row>
      <field column="date">2023-07-20</field>
      <field column="name">Charlie</field>
      <field column="city">Celle</field>
      <field column="amount">15.00</field>
      <field column="currency">GBP</field>
      <field column="original amount">11.99</field>
    </row>
  </rows>
</csv>
]]></eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change PR="533 719 834 1066 1605" issue="413 1052" date="2023-07-25"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="parse-json" prefix="fn">
      <fos:signatures>
         <fos:proto name="parse-json" return-type="item()?">
            <fos:arg name="value" type="xs:string?" example="'[22, 23]'"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Parses input supplied in the form of a JSON text, returning the results typically in the form
            of a map or array.</p>
      </fos:summary>
      <fos:rules>
         <p>The first argument is a JSON text as defined in <bibref ref="rfc7159"
            />, in the form of a string or binary value. The function
            parses this input to return an XDM value.</p>

         <p>If <code>$value</code> is the empty sequence, the function returns the empty sequence.</p>

         <note>
            <p>If the input is <code>"null"</code>, the result will also be the empty sequence.</p>
         </note>

        

         <p>The <code>$options</code> argument can be used to control the way in which the parsing
            takes place. The <termref
               def="option-parameter-conventions">option parameter conventions</termref> apply.</p>

         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>

         <fos:options>
            <fos:option key="liberal">
               <fos:meaning>Determines whether deviations from the syntax of RFC7159 are permitted.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false"
                        >
                     The input <rfc2119>must</rfc2119> consist of <phrase>an optional byte order mark (which is ignored) followed by</phrase> a string
                     that conforms to the grammar of <code>JSON-text</code> in <bibref
                        ref="rfc7159"
                        />. An error <rfc2119>must</rfc2119> be raised
                     <errorref
                        class="JS" code="0001"
                     /> if the input does not conform to the grammar.
                  </fos:value>
                  <fos:value value="true"
                        >
                     The input <rfc2119>may</rfc2119> contain deviations from the grammar of <bibref
                        ref="rfc7159"/>,
                     which are handled in an <termref
                        def="implementation-defined"
                        >implementation-defined</termref> way. (Note: some popular
                     extensions include allowing quotes on keys to be omitted, allowing a comma
                     to appear after the last item in an array, allowing leading zeroes in numbers, and allowing control characters such as
                     tab and newline to be present in unescaped form.) Since the extensions accepted
                     are implementation-defined, an error <rfc2119>may</rfc2119> be raised
                     <errorref
                        class="JS" code="0001"
                     /> if the input does not conform to the grammar.
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="duplicates">
               <fos:meaning>Determines the policy for handling duplicate keys in a JSON object.
                  To determine whether keys are duplicates, they are compared using the Unicode codepoint collation, after expanding escape
                  sequences, unless the <phrase><code>escape</code> option is set to <code>true</code></phrase>, in which
                  case keys are compared in escaped form. 
               </fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>use-first</fos:default>
               <fos:values>
                  <fos:value value="reject">
                     An error is raised <errorref
                        class="JS" code="0003"
                     /> if duplicate keys are encountered.
                  </fos:value>
                  <fos:value value="use-first"
                     >
                     If duplicate keys are present in a JSON object, all but the first of a set of duplicates are ignored.
                  </fos:value>
                  <fos:value value="use-last"
                     >
                     If duplicate keys are present in a JSON object, all but the last of a set of duplicates are ignored.
                  </fos:value>
               </fos:values>
            </fos:option>
            
            <!--<fos:option key="retain-order">
               <fos:meaning>Determines whether maps resulting from parsing of JSON objects should retain the input order.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false()</fos:default>
               <fos:values>
                  <fos:value value="false">Any maps resulting from parsing of JSON objects have the <code>ordering</code>
                  property set to <code>undefined</code>.</fos:value>
                  <fos:value value="true">Any maps resulting from parsing of JSON objects have the <code>ordering</code>
                  property set to <code>insertion</code>, and the 
                     <xtermref spec="DM40" ref="dt-entry-order">entry order</xtermref> retains the order
                  of entries in the input.</fos:value>
               </fos:values>
            </fos:option>-->

            <fos:option key="escape">
               <fos:meaning>Determines whether special characters are represented in the XDM output in backslash-escaped form.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">
                     Any <termref def="dt-permitted-character"/> in the input, 
                     whether or not it is represented 
                     in the input by means of an escape sequence, is represented as an unescaped character 
                     in the result. Any other character or codepoint 
                     (for example, an unpaired surrogate) is passed to the <code>fallback</code> function
                        as described below; in the absence of a fallback function, it is replaced by
                        <char>U+FFFD</char>.
                  </fos:value>
                  <fos:value value="true">
                     JSON escape sequences are used in the result to represent special characters in the JSON input, as defined below, 
                     whether or not they were represented using JSON escape sequences in the input.
                     The characters that are considered “special” for this purpose are:
                     <ulist>
                        <item><p>all codepoints in the range <char>U+0000</char> to <char>U+001F</char> 
                           or <char>U+007F</char> to <char>U+009F</char>;</p></item>
                        <item><p>all codepoints that do not represent 
                           <termref def="dt-permitted-character">permitted characters</termref>,
                           including codepoints representing unpaired surrogates;</p></item>
                        <item><p>the character <char>U+005C</char> itself.</p></item>
                     </ulist>
                     
                     Such characters are represented using a two-character
                     escape sequence where available (for example, <code>\t</code>), or a six-character escape sequence otherwise
                     (for example <code>\uDEAD</code>). Characters other than these are not escaped in the result, even if they
                     were escaped in the input.
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="fallback">
               <fos:meaning>
                  Provides a function which is called when the input contains an escape sequence 
                  that represents a character that is not a <termref def="dt-permitted-character"/>. 
                  It is an error to supply the <code>fallback</code> option if the <code>escape</code>
                  option is present with the value <code>true</code>.
               </fos:meaning>
               <fos:type>(fn(xs:string) as xs:anyAtomicType)?</fos:type>
               <fos:default>fn { char(0xFFFD) }</fos:default>
               <fos:values>
                  <fos:value value="User-supplied function">
                     The function is called when the JSON input contains character that 
                     is not a <termref def="dt-permitted-character"/>
                     It is called once for any surrogate
                     that is not properly paired with another surrogate. The untyped atomic item
                     supplied as the argument will always be a two- or six-character escape
                     sequence, starting with a backslash, that conforms to the rules in the JSON grammar
                     (as extended by the implementation if <code>liberal:true()</code> is specified):
                     for example <code>\b</code> or <code>\uFFFF</code> or <code>\uDEAD</code>.
                     <p>By default, the escape sequence is replaced with the Unicode
                     <code>REPLACEMENT CHARACTER</code>. The function is <emph>not</emph>
                     called for an escape sequence that is invalid against the grammar (for example <code>\x0A</code>).
                     The string, which results from invoking <function>fn:string</function> on the result
                     of the function, is inserted into the result in place of the invalid character. The
                     function also has the option of raising a dynamic error by calling <function>fn:error</function>.</p>
                  </fos:value>
               </fos:values>
            </fos:option>
            
            <fos:option key="null" diff="add" at="2024-02-19">
               <fos:meaning>Determines how the JSON <code>null</code> value should be represented.</fos:meaning>
               <fos:type>item()*</fos:type>
               <fos:default>()</fos:default>
               <fos:values>
                  <fos:value value="Value">
                     The supplied XDM value is used to represent the JSON <code>null</code> value.
                     The default representation of <code>null</code> is the empty sequence, which works
                     well in cases where setting a property of an object to <code>null</code> has the
                     same meaning as omitting the property. It works less well in cases where <code>null</code>
                     is used with some other meaning, because expressions such as the lookup operator
                     <code>?</code> flatten the result to a single sequence of items,
                     which means that any entries whose value is the empty sequence effectively disappear.
                     The property can be set to any XDM value; a suggested value is the <code>xs:QName</code>
                     value <code>fn:QName("http://www.w3.org/2005/xpath-functions", "null")</code>,
                     which is recognized by the JSON serialization method as representing the JSON value
                     <code>null</code>.
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="number-parser" diff="add" at="A">
               <fos:meaning>Determines how numeric values should be processed.</fos:meaning>
               <fos:type>(fn(xs:untypedAtomic) as item()?)?</fos:type>
               <fos:default>xs:double#1</fos:default>
               <fos:values>
                  <fos:value value="User-supplied function">
                     The supplied function is called to process the string value of any JSON number
                     in the input. By default, numbers are processed by 
                     converting to <code>xs:double</code> using the XPath casting rules.
                     Supplying the value <code>xs:decimal#1</code> will instead convert to <code>xs:decimal</code>
                     (which potentially retains more precision, but disallows exponential notation), while
                     supplying a function that casts to <code>(xs:decimal | xs:double)</code> will treat
                     the value as <code>xs:decimal</code> if there is no exponent, or as <code>xs:double</code>
                     otherwise. Supplying the value <code>fn:identity#1</code> causes the value to be retained
                     unchanged as an <code>xs:untypedAtomic</code>. 
                     
                     If the <code>liberal</code> option is <code>false</code> (the default), then
                     the supplied <code>number-parser</code> is called if and only if the value conforms 
                     to the JSON grammar for numbers (for example,
                     a leading plus sign and redundant leading zeroes are not allowed). If the <code>liberal</code>
                     option is <code>true</code> then it is also called if the value conforms to an
                     <termref def="implementation-defined"/> extension of this grammar.
                  </fos:value>
               </fos:values>
            </fos:option>
         </fos:options>

         

         <p>The various structures that can occur in JSON are transformed recursively to XDM values
            as follows:</p>

         <olist>
            <item>
               <p>A JSON <emph>object</emph> is converted to a map. 
                  The entries in the map correspond to the key/value
                  pairs in the JSON object. The key is always of type <code>xs:string</code>; the
                  associated value may be of any type, and is the result of converting the JSON
                  value by recursive application of these rules. For example, the JSON text
                     <code>{ "x": 2, "y": 5 }</code> is transformed to the value
                     <code>{ "x": 2, "y": 5 }</code>.</p>
               <p>If duplicate keys are encountered in a JSON <emph>object</emph>, they are handled
                  as determined by the <code>duplicates</code> option defined above.</p>
               <p>The order of entries is retained.</p>
            </item>
            <item>
               <p>A JSON <emph>array</emph> is transformed to an array whose members are the result of converting
                  the corresponding member of the array by recursive application of these rules. For
                  example, the JSON text <code>[ "a", "b", null ]</code> is transformed (by default) to the value
                     <code>[ "a", "b", () ]</code>.</p>
            </item>
            <item>
               <p>A JSON <emph>string</emph> is converted to an <code>xs:string</code> value. 
               <phrase>The handling of special characters depends on the
               <code>escape</code> and <code>fallback</code> options, as described in the table above.</phrase></p>
            </item>
            <item>
               <p>A JSON <emph>number</emph> is <phrase diff="add" at="A">processed using the function supplied
                  in the <code>number-parser</code> option; by default it is</phrase> converted to an <code>xs:double</code> value using
                  the rules for casting from <code>xs:string</code> to <code>xs:double</code>.</p>
               <note><p>The casting rules leave implementations some flexibility as to how values should be handled when they
               are too large to represent as an <code>xs:double</code>. It is <rfc2119>recommended</rfc2119>
               that when parsing JSON, out-of-range values should be converted to positive or negative infinity. 
               This option enables round-tripping
               behavior, since the JSON serialization method represents positive and negative infinity as <code>1e9999</code>
               or <code>-1e9999</code> respectively.</p></note>
               <note><p>Round-tripping of NaN can be achieved by setting the option <code>"null": number("NaN")</code></p></note>
            </item>
            <item>
               <p>The JSON <emph>boolean</emph> values <code>true</code> and <code>false</code> are
                  converted to the corresponding <code>xs:boolean</code> values.</p>
            </item>
            <item>
               <p diff="chg" at="2024-02-19">The JSON value <emph>null</emph> is converted 
                  to the value given by the <code>null</code> option, which defaults to an 
                  empty sequence.</p>
            </item>
         </olist>


      </fos:rules>
      <fos:errors>
         <p>A dynamic error <errorref class="JS" code="0001"
               /> occurs if the value of
               <code>$value</code> does not conform to the JSON grammar, unless the option
            <code>"liberal":true()</code> is present and the processor chooses to accept the deviation.</p>

         <p>A dynamic error <errorref class="JS" code="0003"
               /> occurs if the option
            <code>"duplicates": "reject"</code> is present and the value of
            <code>$value</code> contains a JSON object with duplicate keys.</p>

         <p>A dynamic error <errorref class="JS" code="0005"
               /> occurs if the <code>$options</code>
            map contains an entry whose key is defined in this specification and whose value is not valid for that key,
         or if it contains an entry with the key <code>fallback</code> when the option <code>"escape":true()</code>
         is also present.</p>
      </fos:errors>
      <fos:notes>
         <p>The result of the function will be an instance of one of the following types. An
               <code>instance of</code> test (or in XQuery, <code>typeswitch</code>) can be used to
            distinguish them:</p>
         <ulist>
            <item>
               <p><code>map(xs:string, item()?)</code> for a JSON object</p>
            </item>
            <item>
               <p><code>array(item()?)</code> for a JSON array</p>
            </item>
            <item>
               <p><code>xs:string</code> for a JSON string</p>
            </item>
            <item>
               <p><code>xs:double</code> for a JSON number</p>
            </item>
            <item>
               <p><code>xs:boolean</code> for a JSON boolean</p>
            </item>
            <item>
               <p><code>empty-sequence()</code> for a JSON null (or for empty input)</p>
            </item>
         </ulist>
         
         <p>If the source of the JSON input is a resource accessible by URI, then it may be preferable
         to use the <function>fn:json-doc</function> function. If the source is a binary value (<code>xs:hexBinary</code>
         or <code>xs:base64Binary</code>) then this can first be decoded as a string using the functions
         <function>bin:infer-encoding</function> and <function>bin:decode-string</function>.</p>
         
         <p>If the input starts with a byte order mark, this function ignores it. The byte order mark may have been added
         to the data stream in order to facilitate decoding of an octet stream to a character string, but since this function
         takes a character string as input, the byte order mark serves no useful purpose.</p>

         <p>The possibility of the input containing characters that are not valid in XML (for example, unpaired surrogates)
            arises only when such characters are expressed using JSON escape sequences. This is because the input to the function
            is an instance of <code>xs:string</code>, which by definition (see <xspecref spec="DM40" ref="xml-and-xsd-versions"/>)
            cannot contain unpaired surrogates.</p>
         
         <p>The serializer provides an option to output data in <term>json-lines</term> format. This is a format for structured data
            containing one JSON value (usually but not necessarily a JSON object) on each line. There is no corresponding
         option to parse <term>json-lines</term> input, but this can be achieved using the expression
         <code>unparsed-text-lines($uri) =!> parse-json()</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>parse-json('{ "x": 1, "y": [ 3, 4, 5 ] }')</fos:expression>
               <fos:result>{ "x": 1e0, "y": [ 3e0, 4e0, 5e0 ] }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-json('"abcd"')</fos:expression>
               <fos:result>"abcd"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>parse-json('{ "x": "\\", "y": "\u0025" }')</fos:expression>
               <fos:result>{ "x": "\", "y": "%" }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json(
  '{ "x": "\\", "y": "\u0025" }',
  { 'escape': true() }
)</eg></fos:expression>
               <fos:result>{ "x": "\\", "y": "%" }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json(
  '{ "x": "\\", "y": "\u0000" }'
)</eg></fos:expression>
               <fos:result>{ "x": "\", "y": char(0xFFFD) }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json(
  '{ "x": "\\", "y": "\u0000" }',
  { 'escape': true() }
)</eg></fos:expression>
               <fos:result>{ "x": "\\", "y": "\u0000" }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json(
  '{ "x": "\\", "y": "\u0000" }',
  { 'fallback': fn($s) { '[' || $s || ']' } }
)</eg></fos:expression>
               <fos:result>{ "x": "\", "y": "[\u0000]" }</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json(
  "1984.2",
  { 'number-parser': fn { xs:integer(round(.)) } }
)</eg></fos:expression>
               <fos:result>1984</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json(
  '[ 1, -1, 2 ]',
  { 'number-parser': fn  { boolean(. >= 0) } }
)</eg></fos:expression>
               <fos:result>[ true(), false(), true() ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>parse-json('[ "a", null, "b" ]',
  { 'null': #fn:null }
)</eg></fos:expression>
               <fos:result>[ "a", #fn:null, "b" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="414" PR="546" date="2023-07-25">
            <p>The rules regarding use of non-XML characters in JSON texts have been relaxed.</p>
         </fos:change>
         <fos:change issue="960" PR="1028" date="2024-02-20">
            <p>An option is provided to control how the JSON <code>null</code> value should be handled.</p>
         </fos:change>
         <fos:change issue="973 1037" PR="975 1058 1246" date="2024-03-12">
            <p>An option is provided to control how JSON numbers should be formatted.</p>
         </fos:change>
         <fos:change issue="641" PR="2387" date="2026-01-16">
            <p>It is now recommended that out-of-range <code>xs:double</code> values should translate
               to positive or negative infinity.</p>
         </fos:change>
         <fos:change issue="1555" PR="1565" date="2024-11-11">
            <p>The default for the <code>escape</code> option has been changed to <code>false</code>. The 3.1
            specification gave the default value as <code>true</code>, but this appears to have been an error,
            since it was inconsistent with examples given in the specification and with tests in the test suite.</p>
         </fos:change>
         <fos:change issue="1651" PR="1703" date="2025-01-14">
            <p>The order of entries in maps is retained.</p>
         </fos:change>
         <!--<fos:change issue="748" PR="2013" date="2025-05-20">
            <p>Support for binary input has been added.</p>
         </fos:change>-->
      </fos:changes>
   </fos:function>

   <fos:function name="json-doc" prefix="fn">
      <fos:signatures>
         <fos:proto name="json-doc" return-type="item()?">
            <fos:arg name="source" type="xs:string?" example="'JSONTestSuite/test_parsing/y_number.json'"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="executable-base-uri">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Reads an external resource containing JSON, and returns the result of parsing the resource as JSON.</p>
      </fos:summary>
      <fos:rules>
         <p>The effect of the two-argument function call <code>fn:json-doc($H, $M)</code>is equivalent to the function composition
            <code>fn:unparsed-text($H) => fn:parse-json($M)</code>, except that:</p>
         
         <ulist>
            <item><p>The function may accept a resource in any encoding. [RFC 7159] requires 
               UTF-8, UTF-16, or UTF-32 to be accepted, but it is not an error if a different encoding 
               is used. Unless external encoding information is available, the function must assume 
               that the encoding is one of UTF-8, UTF-16, or UTF-32, and must distinguish these cases 
               by examination of the initial octets of the resource.</p></item>
            <item><p>Having established the encoding, the function must accept any codepoint that
               can validly occur in a JSON text, with the exception of unpaired surrogates.</p></item>
         </ulist>
         
         
         <p>If <code>$source</code> is the empty sequence, the function returns the empty sequence.</p>
         <note><p>The ability to access external resources depends on whether the
         calling code is <xtermref spec="XP40" ref="dt-trusted"/>.</p></note>
      </fos:rules>
      <fos:errors>
         <p>The function may raise any error defined for the <function>fn:unparsed-text</function> or <function>fn:parse-json</function>
         functions.</p>
      </fos:errors>
      <fos:notes>
         <p>An initial byte order mark is dropped, as with the <function>fn:unparsed-text</function> function.</p>
         <p>If the input cannot be decoded (that is, converted into a sequence of Unicode codepoints, which may or may not represent characters),
            then a dynamic error occurs as with the <function>fn:unparsed-text</function> function.</p>
         <p>If the input can be decoded,
            then the possibility still arises that the resulting sequence of codepoints includes codepoints that are
            not <termref def="dt-permitted-character">permitted characters</termref>. Such codepoints are translated into JSON escape sequences (for example, <code>\uFFFF</code>),
            and the JSON escape sequence is then passed to the fallback function specified in the <code>$options</code> argument, which in turn
            defaults to a function that returns <char>U+FFFD</char>.</p>
         
         <p>The function <rfc2119>may</rfc2119> accept a resource in any encoding. <bibref ref="rfc7159"/> requires
               UTF-8, UTF-16, or UTF-32 to be accepted, but it is not an error if a different encoding is used.
               The function detects the encoding using the same rules as the <function>unparsed-text</function>
               function, except that the special handling of media types such as <code>text/xml</code>
            and <code>application/xml</code> may be skipped.</p>
         
         
         
      </fos:notes>
      <fos:changes>
         <fos:change><p>Additional options are available, as defined by <function>fn:parse-json</function>.</p></fos:change>

         <fos:change issue="414" PR="546" date="2023-07-25">
            <p>It is no longer automatically an error if the input
               contains a codepoint that is not valid in XML. Instead, the codepoint
            must be a <termref def="dt-permitted-character"/>. The set of permitted
            characters is <termref def="implementation-defined"/>, but it is
            <rfc2119>recommended</rfc2119> that all Unicode characters should 
               be accepted.</p>
         </fos:change>
      </fos:changes>
      
   </fos:function>
   
   <!--<fos:function name="json" prefix="fn">
      <fos:signatures>
         <fos:proto name="json" return-type="xs:string">
            <fos:arg name="input" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Creates a JSON representation of an arbitrary XDM value.</p>
      </fos:summary>
      <fos:rules>
         <p>This function returns a string, in JSON format, containing a representation of the
         supplied input <code>$input</code>. The function is error-free (it accepts any input sequence
         whatsoever), but it is not lossless: there are cases when two different XDM values will
         have the same JSON representation. For example, the sequence <code>(1, 2)</code>
            and the array <code>[ 1, 2 ]</code> are both output as <code>[ 1, 2 ]</code>.</p>
         
         <p>The entries that may appear in the <code>$options</code> map are as follows:</p>
         
         <fos:options>
            <fos:option key="indent">
               <fos:meaning>Determines whether additional whitespace should be added to the output to improve readability.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
               <fos:values>
                  <fos:value value="false">
                     The processor must not insert any insignificant whitespace between JSON tokens.
                  </fos:value>
                  <fos:value value="true">
                     The processor <rfc2119>may</rfc2119> insert whitespace between JSON tokens in order to improve readability.
                     The specification imposes no constraints on how this is done.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="element-map">
               <fos:meaning>Determines whether elements whose children are element nodes with distinct
                  names should be treated specially.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
               <fos:values>
                  <fos:value value="false">
                     The processor treats such elements in the same way as any other element.
                  </fos:value>
                  <fos:value value="true">
                     The processor generates a JSON object in which the child element names are used
                     as JSON property names.
                  </fos:value>
               </fos:values>
            </fos:option>
         </fos:options>
         
         
         <p>An input sequence is handled as follows:</p>
         <ulist>
            <item><p>An empty sequence is output as the JSON value null.</p></item>
            <item><p>A singleton sequence is output following the rules for processing items, below.</p></item>
            <item><p>A sequence of two or more items results in a JSON array, whose members are constructed
            from the items by applying the rules below.</p></item>
         </ulist>
         
         <p>Items are processed as follows:</p>
         
         <ulist>
            <item>
               <p><emph>atomic items</emph></p>
               <ulist>
                  <item><p>An <code>xs:boolean</code> value is output as the JSON value <code>true</code> or <code>false</code>.</p></item>
                  <item><p>A numeric value, other than <code>INF</code>, <code>-INF</code>, or <code>NaN</code>,
                  is output as a JSON number.</p></item>
                  <item><p>Any other atomic item is cast to <code>xs:string</code>, and the result is output as a JSON string,
                  escaped as described below.</p></item>
               </ulist>
            </item>
            <item>
               <p><emph>Nodes</emph></p>
               <ulist>
                  <item>
                     <p><emph>Document nodes</emph></p>
                     <p>A document node is output as a JSON object with two properties, in order:</p>
                     <ulist>
                        <item><p>A property <code>#document</code> set to the value of the base URI of the document
                           if available, or an empty string otherwise..</p></item>
                        <item><p>A property <code>#content</code> whose value follows the rules for
                        outputting the content of an element node, given below.</p></item>                       
                     </ulist>
                  </item>
                  <item>
                     <p><emph>Element nodes</emph></p>
                     <p>An element node is output as a JSON object with the following properties, in order:</p>
                     <ulist>
                        <item>
                           <p><code>#element</code> set to the local name of the element.</p>
                        </item>
                        <item>
                           <p>If the element name has a prefix, <code>#prefix</code>, set to the value of the prefix.</p>
                        </item>
                     
                        <item>
                           <p>If the element name is in a namespace, <code>#namespace</code>, set to the value of the 
                           namespace URI.</p>
                        </item>
                        <item>
                           <p>For each attribute of the element, in arbitrary order, a property whose
                              name is derived from the attribute name as follows:</p>
                                 <ulist>
                                    <item><p>If the attribute name is in no namespace, then <code>"@"</code> followed
                                    by the local name.</p></item>
                                    <item><p>If the attribute name is in the XML namespace, then <code>"@xml:"</code> followed
                                       by the local name.</p></item>
                                    <item><p>Otherwise <code>"@Q{uri}local"</code> where <code>uri</code> is the namespace
                                       URI and <code>local</code> is the local name.</p></item>
                                 </ulist>
                              
                                 <p>The property value is the result of atomizing the attribute node and applying the
                                 <function>fn:json</function> function to the result. (For untyped attributes, the result
                                 will always be a single string.)</p>
                              
                           
                        </item>
                        <item>
                           <p>The children of the element are processed as follows:</p>
                           <ulist>
                              <item>
                                 <p>If there are no children, nothing is output.</p>
                              </item>
                              <item>
                                 <p>If the element has a type annotation that is a simple type, or if its content
                                 comprises a single text node, then a property <code>#value</code> set to the result
                                 of atomizing the element node and applying the <function>fn:json</function> function
                                 to the result.</p>
                              </item>
                              <item>
                                 <p>If (a) the children consist exclusively of elements and whitespace-only
                                 text nodes, and (b) the child element nodes are all in the same namespace, or all in no
                                 namespace, and (c) each child element has a local name that is distinct from the local
                                 name of any other child, and (d) the <code>element-map</code> option is not
                                    present in <code>$options</code> with the value <code>false</code>,
                                    then a property <code>#content</code> whose value is a JSON
                                 object having one property for each child element node. The name of this property
                                 is the local name of the element, and the value of the property is obtained by applying
                                 these rules recursively, except that for an empty element, the value is represented
                                 as JSON <code>null</code>.</p>
                              </item>
                              <item><p>Otherwise, a property <code>#content</code> whose value is an array, with
                              one member for each child node (including whitespace-only text nodes), obtained
                              by applying the <function>fn:json</function> function to that child node.</p></item>
                           </ulist>
                        </item>
                     </ulist>
                  </item>
                  <item>
                     <p><emph>Text nodes</emph></p>
                     <p>A JSON object with a single property <code>#text</code> whose value is the
                        string value of the text node.</p>
                  </item>
                  <item>
                     <p><emph>Comment nodes</emph></p>
                     <p>A JSON object with a single property <code>#comment</code> whose value is the
                        string value of the comment.</p>
                  </item>
                  <item>
                     <p><emph>Processing instruction nodes</emph></p>
                     <p>A JSON object with a two properties (in order): <code>#processing-instruction</code> set to the
                        name of the processing instruction, and <code>#data</code> set to the
                        string value of the processing instruction node.</p>
                  </item>
                  <item>
                     <p><emph>Attribute nodes</emph></p>
                     <p>Attribute nodes that are reached via an element node are output as described
                        under “element nodes”, above.</p>
                     <p>Free-standing attribute nodes are output as JSON objects with properties
                     <code>#attribute</code> set to the local name of the attribute, <code>#prefix</code>
                     (if non-empty) set to the prefix of the attribute’s name, <code>#namespace</code>
                     (if non-empty) set to the namespace URI, and <code>#value</code> set to
                        the result of atomizing the attribute value and applying the
                        <function>fn:json</function> function to the result.</p>
                  </item>
                  <item><p><emph>Namespace nodes</emph></p></item>
                  <item><p>Namespace nodes that are reached via an element node result in no output.</p></item>
                  <item><p>Free-standing namespace nodes are output as JSON objects with properties
                  <code>#namespace</code> set to the namespace prefix (<code>""</code> for the default
                  namespace) and <code>#uri</code> set to the namespace URI.</p></item>
               </ulist>            
            </item>
            <item>
               <p><emph>Maps</emph></p>
               <p>An XDM map is output as a JSON object with one property for each entry in the map.</p>
               <p>The property name is derived from the key value by converting the value to a string
               and applying escaping rules. If the property name thus generated is the same as a previously output
               property name, then it is made unique by appending <code>"(N)"</code> where <var>N</var> is the smallest
               positive integer that makes the resulting value unique.</p>
               <p>The property value is derived by applying the <function>fn:json</function> function to the value in the map entry.</p>
               
               <note><p>Conflicts between property names can arise because the XDM model allows keys of different types,
                  for example the <code>xs:date</code> value <code>2020-12-31</code> and the string value 
                  <code>"2020-12-31"</code> can co-exist. The map <code>{ xs:duration('PTD'): 20, "P1D": 30 }</code>
                  is converted to the JSON string <code>{ "P1D": 20, "P1D(1)": 30 }</code> or 
                  <code>{ "P1D": 30, "P1D(1)": 20 }</code>, depending on the (unpredictable) order in which the
               entries in the map are processed.</p></note>
               <note><p>Because the order of entries in a map is unpredictable, the order in which the
               properties are listed in the JSON output is also unpredictable.</p></note>
               </item>
            <item>
               <p><emph>Arrays</emph></p>
               <p>An XDM array is output as a JSON array. Each member of the XDM array generates one entry in the
                  JSON array, in order, obtained by applying the <function>fn:json</function> function to the XDM array member.</p>              
            </item>
            <item>
               <p><emph>Functions</emph></p>
               <p>An XDM function, other than a map or array, is output as a JSON object with the following
               properties:</p>
               <ulist>
                  <item><p><code>#function</code>, set to the local name of the function
                  if it has a name, or the empty string otherwise.</p></item>
                  <item><p><code>#namespace</code>, set to the namespace URI of the function. The property
                  is omitted for an anonymous function.</p></item>
                  <item><p><code>#arity</code>, set to the arity of the function as a JSON number.</p></item>
                  <item><p><code>#arguments</code> whose value is an array
                  of strings, which identify the names and types of the function arguments,
                  in the format <code>$Q{uri}local as SequenceType</code>: for example 
                     <code>[ "$x as double", "$y as string" ]</code>. Namespace prefixes must not be used:
                     unprefixed element names and variable names are taken to be in no namespace, and unprefixed
                     type names are taken to be in the namespace <code>http://www.w3.org/2001/XMLSchema</code>.
                  </p></item>
                  <item><p><code>#result</code> whose value is a string 
                     identifying the type of the function result, using the same conventions as for <code>#arguments</code>.</p></item>
                  <item><p>Optionally at implementer discretion, <code>#implementation</code> whose value is a string 
                     representing the function’s implementation in implementation-defined format.</p></item>
               </ulist>
               <p>Strings are escaped as follows:</p>
               <olist>
                  <item>
                     <p>Any occurrence of backslash is replaced by <code>\\</code></p>
                  </item>
                  
                  <item>
                     <p>Any occurrence of quotation mark, backspace, form-feed, newline, carriage return, or tab is 
                        replaced by <code>\"</code>, <code>\b</code>, <code>\f</code>, <code>\n</code>, <code>\r</code>, or <code>\t</code> respectively; </p>
                  </item>
                  
                  <item>
                     <p>Any other codepoint in the range 1-31 or 127-159 is replaced by an escape in 
                        the form <code>\uHHHH</code> where <code>HHHH</code> is the upper-case hexadecimal representation of the codepoint value.</p>
                  </item>
               </olist>
            </item>
         </ulist>        
      </fos:rules>
      <fos:notes>
         <p>In the JSON output, names of properties defined in this specification are prefixed with <code>#</code>;
         names not so prefixed are derived from names appearing in the input.</p>
         <p>Namespace information may be lost (specifically, namespaces that are declared but not used are
         not retained in the output).</p>
         <p>The distinction between sequences and arrays is lost.</p>
         <p>The distinction between different atomic types is lost, except for the boolean / number / string
         distinction present in JSON.</p>
         <p>In elements whose children are elements with distinct names, whitespace text nodes are lost,
         and the namespace URIs and prefixes of the child elements are lost.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>json(())</fos:expression>
               <fos:result>'null'</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>json(12)</fos:expression>
               <fos:result>'12'</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>json((12, "December"))</fos:expression>
               <fos:result>'[12,"December"]'</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>json(true())</fos:expression>
               <fos:result>'true'</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>json({ "a": 1,"b": number('NaN'), "c": (1, 2, 3) })</fos:expression>
               <fos:result>'{"a":1,"b":"NaN","c":[1,2,3]}'</fos:result>
               <fos:postamble>(or some permutation thereof)</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><![CDATA[json(<a x="2">banana</a>)]]></fos:expression>
               <fos:result>'{"#element":"a","@x":"2","#value":"banana"}'</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><![CDATA[json(<a><b/><c>2</c></a>)]]></fos:expression>
               <fos:result>'{"#element":"a","#content":{"b":null,"c":"2"}}'</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><![CDATA[json(<a><b/><b/><c/></a>)]]></fos:expression>
               <fos:result>'{"#name":"a","#content":[{"#name":"b"},{"#name":"b"},{"#name":"c}]}'</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><![CDATA[json(<a>A <i>nice</i> one!</a>)]]></fos:expression>
               <fos:result>'{"#name":"a","#content":["A ",{"#name":"i", "#value":"nice"}," one!"]}'</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:history>
         <fos:version version="4.0">Proposed for 4.0; not yet reviewed.</fos:version>
      </fos:history>
   </fos:function>
-->

   <fos:function name="size" prefix="array">
      <fos:signatures>
         <fos:proto name="size" return-type="xs:integer">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the number of members in the supplied array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the number of members in the array.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
count(array:members($array))
      </fos:equivalent>
      <fos:notes>
         <p>Note that because an array is an item, the <function>fn:count</function> function
            when applied to an array always returns <code>1</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:size([ "a", "b", "c" ])</fos:expression>
               <fos:result>3</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:size([ "a", [ "b", "c" ] ])</fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:size([])</fos:expression>
               <fos:result>0</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:size([ [] ])</fos:expression>
               <fos:result>1</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="empty" prefix="array">
      <fos:signatures>
         <fos:proto name="empty" return-type="xs:boolean">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the supplied array contains no members.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns <code>true</code> if and only if <code>$array</code> contains no members.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
array:size($array) eq 0
      ]]></fos:equivalent>
      <fos:notes>
         <p>The test for emptiness is not the same as the test used by the
            <code>xsl:on-empty</code> instruction in XSLT. For example, an array 
            is not considered empty by this function if it contains a single
            member that is itself the empty array.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:empty([ "a", "b", "c" ])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:empty([])</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:empty([ [] ])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:empty([ () ])</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="get" prefix="array">
      <fos:signatures>
         <fos:proto name="get" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="position" type="xs:integer"/>
         </fos:proto>
         <fos:proto name="get" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="position" type="xs:integer"/>
            <fos:arg name="default" type="item()*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the value at the specified position in the supplied array
            (counting from 1).</p>
      </fos:summary>
      <fos:rules>
         <p diff="chg" at="2022-12-16">Informally, the function returns the member at a specified position in the array.</p>
         
         <p>If <code>$position</code> is out of bounds (that is, if
         it is less than one or greater than <code>array:size($array)</code>), then the effect 
            depends on the number of arguments:</p>
         
         <ulist>
            <item><p>When there are two arguments, an error is raised (<errorref class="AY" code="0001"/>).</p></item>
            <item><p>When there are three arguments, the value of <code>$default</code> is returned.</p></item>
         </ulist>

         <ednote><edtext>Provide separate "formal equivalents" for the two variants.</edtext></ednote>
      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false">
(: For the two-argument form: :)           
    if ($position = (1 to array:size($array)))
    then items-at(array:members($array), $position) => map:get('value'))
    else error(),
(: For the three-argument form: :)           
    if ($position = (1 to array:size($array)))
    then items-at(array:members($array), $position) => map:get('value'))
    else $default
      </fos:equivalent>
      <fos:errors>
         <p>In the absence of a <code>$default</code> argument,
            a dynamic error occurs <errorref class="AY" code="0001"
               /> if <code>$position</code> is not in the range <code>1 to
               array:size($array)</code> inclusive.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>[ "a", "b", "c" ] => array:get(2)</fos:expression>
               <fos:result>"b"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>[ "a", [ "b", "c" ] ] => array:get(2)</fos:expression>
               <fos:result>[ "b", "c" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>[ "a" ] => array:get(1, ())</fos:expression>
               <fos:result>"a"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>[ "a" ] => array:get(2, ())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1363" PR="289 1901">
            <p>A third argument is added, allowing user control of how index-out-of-bounds
            conditions should be handled.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="put" prefix="array">
      <fos:signatures>
         <fos:proto name="put" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="position" type="xs:integer" usage="inspection"/>
            <fos:arg name="member" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all the members of a supplied array, except for one member which is replaced with a new value.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the result is an array whose size is <code>array:size($array)</code>, in which all
            members in positions other than <code>$position</code> are the same as the members in the corresponding position
            of <code>$array</code>, and the member in position <code>$position</code> is <code>$member</code>.</p>
         

      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
$array 
=> array:remove($position) 
=> array:insert-before($position, $member)
       ]]></fos:equivalent>
      <fos:errors>
         <p>A dynamic error occurs <errorref class="AY" code="0001"
               /> if <code>$position</code> is not in the range <code>1 to
            array:size($array)</code> inclusive.</p>
         <p>This error will always occur if <code>$array</code> is empty.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:put([ "a", "b", "c" ], 2, "d")</fos:expression>
               <fos:result>[ "a", "d", "c" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:put([ "a", "b", "c" ], 2, ("d", "e"))</fos:expression>
               <fos:result>[ "a", ("d", "e"), "c" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:put([ "a" ], 1, [ "d", "e" ])</fos:expression>
               <fos:result>[ [ "d", "e" ] ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   
   

   <fos:function name="append" prefix="array">
      <fos:signatures>
         <fos:proto name="append" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="member" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all the members of a supplied array, plus one additional member at the end.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the result is an array whose size is <code>array:size($array) + 1</code>, in which all
            members in positions 1 to <code>array:size($array)</code> are the same as the members in the corresponding position
            of <code>$array</code>, and the member in position <code>array:size($array) + 1</code> is <code>$member</code>.</p>
         <!--<p diff="chg" at="A">More formally, the result is the value of the expression
            <code>array:of-members((array:members($array), { 'value': $member }))</code>.</p>-->

      </fos:rules>
      <fos:equivalent style="dm-primitive">
         dm:array-append($array, $member)
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:append([ "a", "b", "c" ], "d")</fos:expression>
               <fos:result>[ "a", "b", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:append([ "a", "b", "c" ], ("d", "e"))</fos:expression>
               <fos:result>[ "a", "b", "c", ("d", "e") ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:append([ "a", "b", "c" ], [ "d", "e" ])</fos:expression>
               <fos:result>[ "a", "b", "c", [ "d", "e" ] ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="join" prefix="array">
      <fos:signatures>
         <fos:proto name="join" return-type="array(*)">
            <fos:arg name="arrays" type="array(*)*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Concatenates the contents of several arrays into a single array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function concatenates the members of several arrays into a single array.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
$arrays
=> for-each(fn($array) { array:members($array) })
=> array:of-members()
      ]]></fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:join(())</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:join([ 1, 2, 3 ])</fos:expression>
               <fos:result>[ 1, 2, 3 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:join(([ "a", "b" ], [ "c" ]))</fos:expression>
               <fos:result>[ "a", "b", "c" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:join(([ "a", "b" ], [ "c" ], []))</fos:expression>
               <fos:result>[ "a", "b", "c" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:join(([ "a", "b" ], [ [ "c" ] ]))</fos:expression>
               <fos:result>[ "a", "b", [ "c" ] ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array { 1 to 3 }
=> array:split()
=> array:join()</eg></fos:expression>
               <fos:result>[ 1, 2, 3 ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="subarray" prefix="array">
      <fos:signatures>
         <fos:proto name="subarray" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="start" type="xs:integer"/>
            <fos:arg name="length" type="xs:integer?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all members from a supplied array starting at a supplied
            position, up to a specified length.</p>
      </fos:summary>
      <fos:rules>
         <p>Except in error cases, 
            the two-argument version of the function returns the same result as the three-argument
            version when called with <code>$length</code> equal to the value of
            <code>array:size($array) - $start + 1</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false" arity="3"><![CDATA[
$array
=> array:members()
=> subsequence($start, $length)
=> array:of-members()
      ]]></fos:equivalent>     
      <fos:errors>
         <p>A dynamic error is raised <errorref class="AY" code="0001"
                  /> if <code>$start</code> is less than one
            <phrase>or greater than <code>array:size($array) + 1</code></phrase>.</p>
         <p>For the three-argument version of the function:</p>
         <ulist>
            <item>
               <p>A dynamic error is raised <errorref class="AY" code="0002"
                     /> 
               if <code>$length</code> is less than zero.</p>
            </item>
            <item>
               <p>A dynamic error is raised <errorref class="AY" code="0001"
                     /> 
               if <code>$start + $length</code> is greater than <code>array:size($array) + 1</code>.</p>
            </item>
         </ulist>
      </fos:errors>
      <fos:notes>
         <p>The value of <code>$start</code> can be equal to <code>array:size($array) + 1</code> provided that <code>$length</code>
         is either equal to zero or omitted. In this case the result will be the empty array.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:subarray([ "a", "b", "c", "d" ], 2)</fos:expression>
               <fos:result>[ "b", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:subarray([ "a", "b", "c", "d" ], 5)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:subarray([ "a", "b", "c", "d" ], 2, 0)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:subarray([ "a", "b", "c", "d" ], 2, 1)</fos:expression>
               <fos:result>[ "b" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:subarray([ "a", "b", "c", "d" ], 2, 2)</fos:expression>
               <fos:result>[ "b", "c" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:subarray([ "a", "b", "c", "d" ], 5, 0)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:subarray([], 1, 0)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change>
            <p>Supplying the empty sequence as the value of an optional argument is equivalent to
            omitting the argument.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="index-of" prefix="array">
      <fos:signatures>
         <fos:proto name="index-of" return-type="xs:integer*">
            <fos:arg name="array" type="array(*)"/>
            <fos:arg name="target" type="item()*"/>
            <fos:arg name="collation" type="xs:string?" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="2">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:properties arity="3">
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations static-base-uri implicit-timezone">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a sequence of positive integers giving the positions within the array
               <code>$array</code> of members that are equal to <code>$target</code>.</p>
      </fos:summary>
      <fos:rules>
         
         <p>Informally, all members of <code>$array</code> are compared with <code>$target</code>.
            An array member is compared to the target value using the rules of the
            <function>fn:deep-equal</function> function, with the specified (or defaulted) collation.
            The index position of the member is included in the result sequence if the
            comparison returns true.
         </p>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>. This collation is used when string comparison is required.</p>
         <p>The first member in an array is at position 1, not position 0.</p>
         <p>The result sequence is in ascending numeric order.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
array:index-where($array, deep-equal(?, $target, $collation))
      </fos:equivalent>
      <fos:notes>
         <p>If <code>$array</code> is the empty array, or if no member in
            <code>$array</code> matches <code>$target</code>, then the function returns the empty
            sequence.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:index-of([ 10, 20, 30, 30, 20, 10 ], 20)</fos:expression>
               <fos:result>2, 5</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>array:index-of([ (), 1, (5, 6), (6, 7) ], (6, 7))</fos:expression>
               <fos:result>4</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
array:index-of(
  [ "a", ("b", "C"), "d" ],
  ("B", "c"),
  "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
)
</eg></fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
array:index-of(
  [ '1', xs:untypedAtomic('1'), 1, current-date() ],
  '1'
)</eg></fos:expression>
               <fos:result>1, 2</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="260 1096" PR="968 1295" date="2024-02-06"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="index-where" prefix="array">
      <fos:signatures>
         <fos:proto name="index-where" return-type="xs:integer*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="predicate" type="fn(item()*, xs:integer) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the positions in an input array of members that match a supplied predicate.</p>
      </fos:summary>
      <fos:rules>
         
         <p>The result of the function is a sequence of integers, in monotonic ascending order, representing
            the 1-based positions in the input array of those members for which the supplied predicate function
            returns <code>true</code>. A return value of <code>()</code> is treated as <code>false</code>.</p>
 
      </fos:rules>
      
      <fos:equivalent style="xpath-expression">
dm:iterate-array($array, fn($member, $pos) {
  if ($predicate($member, $pos)) { $pos }
})   
      </fos:equivalent>
      
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:index-where([], boolean#1)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:index-where([ 0, (), 4, 9 ], boolean#1)</fos:expression>
               <fos:result>3, 4</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:index-where(
  array { 1 to 10 },
  function { . mod 2 = 0 }
)</eg></fos:expression>
               <fos:result>2, 4, 6, 8, 10</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:index-where(
  [ "January", "February", "March", "April",
    "May", "June", "July", "August", "September",
    "October", "November", "December" ],
  contains(?, "r")
)</eg></fos:expression>
               <fos:result>1, 2, 3, 4, 9, 10, 11, 12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:index-where(
  [ (1, 2, 3), (4, 5, 6), (7, 8) ],
  fn($m) { count($m) = 3 }
)</eg></fos:expression>
               <fos:result>1, 2</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[array:index-where(
  [ 1, 8, 2, 7, 3 ],
  fn($member, $pos) { $member < 5 and $pos > 2 }
)]]></eg></fos:expression>
               <fos:result>3, 5</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="114" PR="258" date="2022-12-13"><p>New in 4.0</p></fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="slice" prefix="array">
      <fos:signatures>
         <fos:proto name="slice" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="start" type="xs:integer?" default="0" note="default-on-empty"/>
            <fos:arg name="end" type="xs:integer?" default="0" note="default-on-empty"/>
            <fos:arg name="step" type="xs:integer?" default="0" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing selected members of a supplied input array based on their position.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the array is converted to a sequence, the function <function>fn:slice</function>
         is applied to this sequence, and the resulting sequence is converted back to an array.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
$array 
=> array:members() 
=> slice($start, $end, $step) 
=> array:of-members()
       ]]></fos:equivalent>
      <fos:notes>

         <p>Note that unlike other operations on arrays, there are no out-of-bounds errors for inappropriate
         values of <code>$start</code>, <code>$end</code>, or <code>$step</code>.</p>
      </fos:notes>
      
      <fos:examples>
         <fos:variable name="in" id="a-slice" as="array(xs:string)" select="[ 'a', 'b', 'c', 'd', 'e' ]"/>
         <fos:example>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 2, end := 4)</fos:expression>
               <fos:result>[ "b", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 2)</fos:expression>
               <fos:result>[ "b", "c", "d", "e" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, end := 2)</fos:expression>
               <fos:result>[ "a", "b" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 3, end := 3)</fos:expression>
               <fos:result>[ "c" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 4, end := 3)</fos:expression>
               <fos:result>[ "d", "c" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 2, end := 5, step := 2)</fos:expression>
               <fos:result>[ "b", "d" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 5, end := 2, step := -2)</fos:expression>
               <fos:result>[ "e", "c" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 2, end := 5, step := -2)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 5, end := 2, step := 2)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in)</fos:expression>
               <fos:result>[ "a", "b", "c", "d", "e" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := -1)</fos:expression>
               <fos:result>[ "e" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := -3)</fos:expression>
               <fos:result>[ "c", "d", "e" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, end := -2)</fos:expression>
               <fos:result>[ "a", "b", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := 2, end := -2)</fos:expression>
               <fos:result>[ "b", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := -2, end := 2)</fos:expression>
               <fos:result>[ "d", "c", "b" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := -4, end := -2)</fos:expression>
               <fos:result>[ "b", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := -2, end := -4)</fos:expression>
               <fos:result>[ "d", "c", "b" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := -4, end := -2, step := 2)</fos:expression>
               <fos:result>[ "b", "d" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice($in, start := -2, end := -4, step := -2)</fos:expression>
               <fos:result>[ "d", "b" ]</fos:result>
            </fos:test>
            <fos:test use="a-slice">
               <fos:expression>array:slice([ "a", "b", "c", "d" ], 0)</fos:expression>
               <fos:result>[ "a", "b", "c", "d" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="63" PR="477" date="2023-05-09"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="remove" prefix="array">
      <fos:signatures>
         <fos:proto name="remove" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="positions" type="xs:integer*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all the members of the supplied array, except for the 
            members at specified positions.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function returns an array of size <phrase><code>array:size($array) - fn:count(fn:distinct-values($positions))</code></phrase> 
            containing all members from <code>$array</code>
            except the members whose position (counting from 1) is present in the sequence <code>$positions</code>.
         The order of the remaining members is preserved.</p>
         <!--<p diff="chg" at="A">More formally, the result of the function, except in error cases, is given by the expression
            <code role="example">array:of-members(array:members($array) => fn:remove($positions))</code>.
         </p>-->
      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false"><![CDATA[
$array 
=> array:members() 
=> remove($positions) 
=> array:of-members()
       ]]></fos:equivalent>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="AY" code="0001"
               /> if any integer in <code>$positions</code> is not in the range <code>1 to
         array:size($array)</code> inclusive. By implication, an error occurs if <code>$array</code> is empty, unless <code>$positions</code>
         is also empty.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:remove([ "a", "b", "c", "d" ], 1)</fos:expression>
               <fos:result>[ "b", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:remove([ "a", "b", "c", "d" ], 2)</fos:expression>
               <fos:result>[ "a", "c", "d" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:remove([ "a" ], 1)</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:remove([ "a", "b", "c", "d" ], 1 to 3)</fos:expression>
               <fos:result>[ "d" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:remove([ "a", "b", "c", "d" ], ())</fos:expression>
               <fos:result>[ "a", "b", "c", "d" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="insert-before" prefix="array">
      <fos:signatures>
         <fos:proto name="insert-before" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="position" type="xs:integer"/>
            <fos:arg name="member" type="item()*" usage="navigation"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all the members of the supplied array, with one additional member at a specified position.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function returns an array of size <code>array:size($array) + 1</code>
            containing all members from <code>$array</code>
            whose position is less than <code>$position</code>, then a new member given by <code>$member</code>, and
            then all members from <code>$array</code> whose position is greater than or equal to <code>$position</code>. 
            Positions are counted from 1.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression" covers-error-cases="false"><![CDATA[
$array 
=> array:members() 
=> insert-before($position, { 'value': $member })
=> array:of-members()
       ]]></fos:equivalent>
      <fos:errors>
         <p>A dynamic error occurs <errorref class="AY" code="0001"
               /> if <code>$position</code> is not in the range <code>1 to
            array:size($array) + 1</code> inclusive.</p>
      </fos:errors>
      <fos:notes>
         <p>Setting <code>$position</code> to 1 has the effect of prepending the new member at the start of the array. Setting <code>$position</code>
         to the value <code>array:size($array) + 1</code> delivers the same result as <code>array:append($array, $member)</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>array:insert-before(
  [ "a", "b", "c", "d" ],
  3,
  ("x", "y")
)</eg></fos:expression>
               <fos:result>[ "a", "b", ("x", "y"), "c", "d" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:insert-before(
  [ "a", "b", "c", "d" ],
  5,
  ("x", "y")
)</eg></fos:expression>
               <fos:result>[ "a", "b", "c", "d", ("x", "y") ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:insert-before(
  [ "a", "b", "c", "d" ],
  3,
  [ "x", "y" ]
)</eg></fos:expression>
               <fos:result>[ "a", "b", [ "x", "y" ], "c", "d" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>



   <fos:function name="head" prefix="array">
      <fos:signatures>
         <fos:proto name="head" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the first member of an array, that is <code>$array(1)</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns first member of <code>$array</code><!--,
            that is the value of <code>array:get($array, 1)</code>-->.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
array:get($array, 1)
      </fos:equivalent>
      <fos:errors>
         <p>A dynamic error occurs <errorref class="AY" code="0001"
            /> if <code>$array</code> is empty.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:head([ 5, 6, 7, 8 ])</fos:expression>
               <fos:result>5</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:head([ [ "a", "b" ], [ "c", "d" ] ])</fos:expression>
               <fos:result>[ "a", "b" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:head([ ("a", "b"), ("c", "d") ])</fos:expression>
               <fos:result>"a", "b"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="foot" prefix="array">
      <fos:signatures>
         <fos:proto name="foot" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the last member of an array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the last member of <code>$array</code>.
            <!--, that is the value of <code>array:get($array, array:size($array))</code>--></p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
array:get($array, array:size($array))
       ]]></fos:equivalent>
      <fos:errors>
         <p>A dynamic error occurs <errorref class="AY" code="0001"
         /> if <code>$array</code> is empty.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:foot([ 5, 6, 7, 8 ])</fos:expression>
               <fos:result>8</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:foot([ [ "a", "b" ], [ "c", "d" ] ])</fos:expression>
               <fos:result>[ "c", "d" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:foot([ ("a", "b"), ("c", "d") ])</fos:expression>
               <fos:result>"c", "d"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="97" PR="250" date="2022-12-07"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="tail" prefix="array">
      <fos:signatures>
         <fos:proto name="tail" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all members except the first from a supplied array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns an array containing all members of the supplied array except the first.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
array:remove($array, 1)
       ]]></fos:equivalent>
      <fos:errors>
         <p>A dynamic error occurs <errorref class="AY" code="0001"
            /> if <code>$array</code> is empty.</p>
      </fos:errors>
      <fos:notes>
         <p>If the supplied array contains exactly one member, the result will be the empty array.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:tail([ 5, 6, 7, 8 ])</fos:expression>
               <fos:result>[ 6, 7, 8 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:tail([ 5 ])</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="trunk" prefix="array">
      <fos:signatures>
         <fos:proto name="trunk" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         <fos:property>special-streaming-rules</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all members except the last from a supplied array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns an array containing all members of the supplied array except the last.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
array:remove($array, array:size($array))
       ]]></fos:equivalent>
      <fos:errors>
         <p>A dynamic error occurs <errorref class="AY" code="0001"
         /> if <code>$array</code> is empty.</p>
      </fos:errors>
      <fos:notes>
         <p>If the supplied array contains exactly one member, the result will be the empty array.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:trunk([ 5, 6, 7, 8 ])</fos:expression>
               <fos:result>[ 5, 6, 7 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:trunk([ 5 ])</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="97" PR="250" date="2022-12-07"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="reverse" prefix="array">
      <fos:signatures>
         <fos:proto name="reverse" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing all the members of a supplied array, but in reverse order.</p>
      </fos:summary>
      <fos:rules>
         <p diff="chg" at="A">The function returns an array with the same number of members
         as <code>$array</code>, but in reverse order.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
$array 
=> array:members() 
=> reverse() 
=> array:of-members()
       ]]></fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:reverse([ "a", "b", "c", "d" ])</fos:expression>
               <fos:result>[ "d", "c", "b", "a" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:reverse([ ("a", "b"), ("c", "d") ])</fos:expression>
               <fos:result>[ ("c", "d"), ("a", "b") ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:reverse([ 1 to 5 ])</fos:expression>
               <fos:result>[ (1, 2, 3, 4, 5) ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:reverse([])</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="for-each" prefix="array">
      <fos:signatures>
         <fos:proto name="for-each" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="action" type="fn(item()*, xs:integer) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns an array whose size is the same as <code>array:size($array)</code>, in which
            each member is computed by applying <code>$action</code> to the corresponding member of
            <code>$array</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function returns an array whose members are obtained by applying 
         the supplied <code>$action</code> function to each member of the input array in turn.</p>
         <p>The <code>$action</code> function is called with two arguments: the first is the
         array member (which in general is an arbitrary sequence), and the second is the 1-based
         integer position.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
array:of-members(
  for-each(array:members($array), 
           fn($member, $pos) {
              { 'value': $action(map:get($member, 'value'), $pos) }
           })
)
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>array:for-each(
  [ "A", "B", 1, 2 ],
  fn($z) { $z instance of xs:integer }
)</eg></fos:expression>
               <fos:result>[false(), false(), true(), true()]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:for-each(
  [ "the cat", "sat", "on the mat" ],
  tokenize#1
)</eg></fos:expression>
               <fos:result>[ ("the", "cat"), "sat", ("on", "the", "mat") ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:for-each(
  [ [ "the", "cat" ], [ "sat" ], [ "on", "the", "mat" ] ],
  array:flatten#1
)</eg></fos:expression>
               <fos:result>[ ("the", "cat"), "sat", ("on", "the", "mat") ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:for-each(
  [ 'one', 'two', 'three' ],
  fn($member, $pos) { $pos || '. ' || $member }
)</eg></fos:expression>
               <fos:result>[ "1. one", "2. two", "3. three" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="516" PR="828" date="2023-11-14">
            <p>The <code>$action</code> callback function now accepts an optional position argument.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="filter" prefix="array">
      <fos:signatures>
         <fos:proto name="filter" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="predicate" type="fn(item()*, xs:integer) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns an array containing those members of the <code>$array</code> for which 
            <code>$predicate</code> returns <code>true</code>. A return value of <code>()</code>
         is treated as <code>false</code>.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function returns an array containing those members of the input
         array that satisfy the supplied predicate.</p>
      </fos:rules>
      <fos:equivalent style="xquery-expression">
array:of-members(
  filter(
    array:members($array),
    fn($item, $pos) { $predicate(map:get($item, 'value'), $pos) }
  )
)      </fos:equivalent>
      <fos:errors>
         <p>As a consequence of the function signature and the function calling rules, a type error occurs if the supplied
            function <code>$function</code> returns anything other than a single <code>xs:boolean</code> item
            or the empty sequence; there is no conversion to an effective boolean value.</p>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>array:filter(
  [ "A", "B", 1, 2 ],
  fn($x) { $x instance of xs:integer }
)</eg></fos:expression>
               <fos:result>[ 1, 2 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:filter(
  [ "the cat", "sat", "on the mat" ],
  function { count(tokenize(.)) > 1 }
)</eg></fos:expression>
               <fos:result>[ "the cat", "on the mat" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:filter([ "A", "B", "", 0, 1 ], boolean#1)</fos:expression>
               <fos:result>[ "A", "B", 1] </fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $array := [ 1, 1, 2, 3, 4, 4, 5 ]
return array:filter(
  $array,
  fn($item, $pos) { $pos > 1 and $item = $array($pos - 1) }
)</eg></fos:expression>
               <fos:result>[ 1, 4 ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="516" PR="828" date="2023-11-14">
            <p>The <code>$predicate</code> callback function now accepts an optional position argument.</p>
         </fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="fold-left" prefix="array">
      <fos:signatures>
         <fos:proto name="fold-left" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="init" type="item()*" usage="navigation"/>
            <fos:arg name="action" type="fn(item()*, item()*) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Evaluates the supplied function cumulatively on successive members of the supplied
            array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function is defined formally below, in terms of the equivalent <function>fn:fold-left</function>
            function for sequences.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
fold-left(
  array:members($array),
  $init,
  fn($result, $member) { $action($result, map:get($member, 'value')) }
)
       ]]></fos:equivalent>
      <fos:notes>
         <p>If the supplied array is empty, the function returns <code>$init</code>.</p>
         <p>If the supplied array contains a single member <code>$m</code>, the function returns <code>$init => $action($m)</code>.</p>
         <p>If the supplied array contains two members <code>$m</code> and <code>$n</code>, the function returns 
            <code>$init => $action($m) => $action($n)</code>; and similarly for an input array with more than two members.</p>
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>array:fold-left(
  [ true(), true(), false() ],
  true(),
  fn($x, $y) { $x and $y }
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>Returns <code>true</code> if every member of the input array has an effective boolean value of <code>true</code>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:fold-left(
  [ true(), true(), false() ],
  false(), 
  fn($x, $y) { $x or $y }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>Returns <code>true</code> if at least one member of the input array has an effective boolean value of <code>true</code>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:fold-left(
  [ 1, 2, 3 ],
  [],
  fn($x, $y) { [ $x, $y ] }
)</eg></fos:expression>
               <fos:result>[ [ [ [], 1 ], 2 ], 3 ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="fold-right" prefix="array">
      <fos:signatures>
         <fos:proto name="fold-right" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
            <fos:arg name="init" type="item()*" usage="navigation"/>
            <fos:arg name="action" type="fn(item()*, item()*) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Evaluates the supplied function cumulatively on successive values of the supplied
            array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function is defined formally below, in terms of the equivalent <function>fn:fold-right</function>
            function for sequences.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
fold-right(
  array:members($array),
  $init,
  fn($member, $result) { $action(map:get($member, 'value'), $result) }
)
       ]]></fos:equivalent>
      <fos:notes>
         <p>If the supplied array is empty, the function returns <code>$init</code>.</p>
         <p>If the supplied array contains a single member <code>$m</code>, the function returns <code>$action($m, $init)</code>.</p>
         <p>If the supplied array contains two members <code>$m</code> and <code>$n</code>, the function returns 
            <code>$action($m, $action($n, $init))</code>; and similarly for an input array with more than two members.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>array:fold-right(
  [ true(), true(), false() ],
  true(),
  fn($x, $y) { $x and $y }
)</eg></fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>Returns <code>true</code> if every member of the input array has an effective boolean value of <code>true</code>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:fold-right(
  [ true(), true(), false() ],
  false(),
  fn($x, $y) { $x or $y }
)</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>Returns <code>true</code> if at least one member of the input array has an effective boolean value of <code>true</code>.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:fold-right(
  [ 1, 2, 3 ],
  [],
  fn($x, $y) { [ $x, $y ] }
)</eg></fos:expression>
               <fos:result>[ 1, [ 2, [ 3, [] ] ] ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>

   <fos:function name="for-each-pair" prefix="array">
      <fos:signatures>
         <fos:proto name="for-each-pair" return-type="array(*)">
            <fos:arg name="array1" type="array(*)" usage="inspection"/>
            <fos:arg name="array2" type="array(*)" usage="inspection"/>
            <fos:arg name="action" type="fn(item()*, item()*, xs:integer) as item()*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns an array obtained by evaluating the supplied function once for each pair of members at the same position in
            the two supplied arrays.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function applies <code>$action</code> to each pair of values in corresponding positions
            within <code>$array1</code> and <code>$array2</code>, ignoring any excess values if one array is longer
            than the other. The results are then assembed into a new array whose size is equal to the shorter of the
            two input arrays.</p>        
      </fos:rules>
      <fos:equivalent style="xpath-expression"><![CDATA[
array:of-members(
  for-each-pair(
    array:members($array1),
    array:members($array2),
    fn($v1, $v2, $pos) {
      { 'value': $action(map:get($v1, 'value'), map:get($v2, 'value'), $pos) }
    }
  )
)       ]]></fos:equivalent>
      <fos:notes>
         <p>If the arrays have different size, excess members in the longer array are ignored.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>array:for-each-pair(
  [ "A", "B", "C" ],
  [ 1, 2, 3 ],
  fn($x, $y) { array { $x, $y }}
)</eg></fos:expression>
               <fos:result>[ [ "A", 1 ], [ "B", 2 ], [ "C", 3 ] ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>let $array := [ "A", "B", "C", "D" ]
return array:for-each-pair(
  $array,
  array:tail($array),
  concat#2
)</eg></fos:expression>
               <fos:result>[ "AB", "BC", "CD" ]</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
array:for-each-pair(
  [ 1, 8, 2 ],
  [ 3, 4, 3 ],
  fn($member1, $member2, $pos) {
    $pos || ': ' || max(($member1, $member2))
  }
)
]]></eg></fos:expression>
               <fos:result>[ "1: 3", "2: 8", "3: 3" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="516" PR="828" date="2023-11-14">
            <p>The <code>$action</code> callback function now accepts an optional position argument.</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="build" prefix="array">
      <fos:signatures>
         <fos:proto name="build" return-type="array(*)">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="action" type="(fn(item(), xs:integer) as item()*)?" usage="inspection" default="fn:identity#1" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns an array obtained by evaluating the supplied function once for each item in the input sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the  function applies the function to each item 
            in the input sequence, and the resulting sequence becomes one member of the returned array.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
array:of-members(
  for-each($input, 
    fn($item, $pos) { { 'value': $action($item, $pos) } }
  )
)
      </fos:equivalent>
      <fos:notes>
         <p>The single-argument function <code>array:build($input)</code> is equivalent to the XPath
         expression <code>array { $input }</code>, but it is useful to have this available as a function.</p>
         <p>The two-argument form facilitates the construction of arrays whose members are arbitrary
         sequences.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:build(1 to 5)</fos:expression>
               <fos:result>[ 1, 2, 3, 4, 5 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:build(1 to 5, fn { 2 * . })</eg></fos:expression>
               <fos:result>[ 2, 4, 6, 8, 10 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:build(1 to 5, fn { 1 to . })</eg></fos:expression>
               <fos:result>[ 1, (1, 2), (1, 2, 3), (1, 2, 3, 4), (1, 2, 3, 4, 5) ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:build(("red", "green", "blue"), characters#1)</eg></fos:expression>
               <fos:result>[ ("r", "e", "d"), ("g", "r", "e", "e", "n"), ("b", "l", "u", "e") ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:build(1 to 5, fn { array { 1 to . } })</eg></fos:expression>
               <fos:result>[ [ 1 ], [ 1, 2 ], [ 1, 2, 3 ], [ 1, 2, 3, 4 ], [ 1, 2, 3, 4, 5 ] ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
array:build(
  (0x41 to 0x48) ! char(.),
  fn($char, $pos) {
    if ($pos mod 2 = 0) then lower-case($char) else $char
  }
)
               </eg></fos:expression>
               <fos:result>[ "A", "b", "C", "d", "E", "f", "G", "h" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="97" PR="250" date="2022-12-07"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="members" prefix="array">
      <fos:signatures>
         <fos:proto name="members" return-type="record(value as item()*)*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Delivers the contents of an array as a sequence of <term>value records</term>.</p>
      </fos:summary>
      <fos:rules>
         <p>The members of the array are delivered as a sequence of <term>value records</term>. 
            A value record is an item that encapsulates an arbitrary sequence <code>$S</code>: specifically
            it is a map comprising a single entry whose key is the <code>xs:string</code> value
            <code>"value"</code> and whose corresponding value is <code>$S</code>. The content encapsulated
         by a value record <code>$V</code> can be obtained using the expression <code>$V?value</code>.</p>
         
         
      </fos:rules>
      <fos:equivalent style="dm-primitive">
            dm:iterate-array($array, array:member#1)
      </fos:equivalent>     
      <fos:notes>
         <p>This function is the inverse of <function>array:of-members</function>.</p>   
      </fos:notes>
 
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:members([])</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:members([ 1 to 5 ])?value</fos:expression>
               <fos:result>1, 2, 3, 4, 5</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:members([ (1, 1), (2, 4), (3, 9), (4, 16), (5, 25) ])
! sum(?value)</eg></fos:expression>
               <fos:result>2, 6, 12, 20, 30</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>let $array := [ "any array" ]
return deep-equal(
  $array,
  array:of-members(array:members($array))
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="29 113 314" PR="360 476"><p>New in 4.0</p></fos:change>
         <fos:change issue="2351">
            <p>The group may remove this function, it is considered <loc href="#at-risk">at risk</loc>.
            </p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="split" prefix="array">
      <fos:signatures>
         <fos:proto name="split" return-type="array(*)*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Delivers the contents of an array as a sequence of single-member arrays.</p>
      </fos:summary>
      <fos:rules>
         <p>The members of the array are delivered as a sequence of 
            <xtermref spec="DM40" ref="dt-single-member-array">single-member arrays</xtermref>. 
            Each returned array encapsulates the value of one member of <code>$array</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
dm:iterate-array($array, fn($member) { array:append([], $member) })        
      </fos:equivalent> 
      <fos:notes>
         <p>The function call <code>array:split($array)</code> produces the same result as the
            expression <code>for member $m in $array return [ $m ]</code>.</p>
         <p>The expression <code>$A => array:split() => array:join()</code>, applied to any array
            <code>$A</code>, returns the original array <code>$A</code>.</p>   
      </fos:notes>
 
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:split([])</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:split([ () ])</fos:expression>
               <fos:result>[ () ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:split([ 1 to 5 ])</fos:expression>
               <fos:result>[ (1, 2, 3, 4, 5) ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:split(
  array { 1 to 5 }
)</eg></fos:expression>
               <fos:result>[ 1 ], [ 2 ], [ 3 ], [ 4 ], [ 5 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:split(
  [ (1, 1), (2, 4), (3, 9), (4, 16), (5, 25) ]
) ! sum(.)</eg></fos:expression>
               <fos:result>2, 6, 12, 20, 30</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>let $array := [ "any array" ]
return deep-equal(
  $array,
  array:join(array:split($array))
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="508" PR="609" date="2023-07-25"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="of-members" prefix="array">
      <fos:signatures>
         <fos:proto name="of-members" return-type="array(*)">
            <fos:arg name="input" type="record(value as item()*)*" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Constructs an array from the contents of a sequence of <term>value records</term>.</p>
      </fos:summary>
      <fos:rules>
         <p>The input items must be <term>value records</term>, as defined in the type signature.  
            A value record is an item that encapsulates 
            an arbitrary sequence <code>$S</code>: specifically
            it is a map comprising a single entry whose key is the <code>xs:string</code> value
            <code>"value"</code> and whose corresponding value is <code>$S</code>. The content encapsulated
            by a value record <code>$V</code> can be obtained using the expression <code>$V?value</code>.</p>
        

      </fos:rules>
      
      <fos:equivalent style="xquery-expression">
fold-left($input, [], fn($array, $record) { 
  array:append($array, map:get($record, 'value'))
})
      </fos:equivalent>

      <fos:notes>
         <p>This function is the inverse of <function>array:members</function>.</p>       
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:of-members(())</fos:expression>
               <fos:result>[]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:of-members({ 'value': (1 to 5) })</fos:expression>
               <fos:result>[ (1, 2, 3, 4, 5) ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:of-members((1 to 5) ! { 'value': . })</fos:expression>
               <fos:result>[ 1, 2, 3, 4, 5 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:of-members((1 to 3) ! { 'value': (., . * .) })</fos:expression>
               <fos:result>[ (1, 1), (2, 4), (3, 9) ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="29 113 314" PR="360 476" date="2023-03-21"><p>New in 4.0</p></fos:change>
         <fos:change issue="2351">
            <p>The group may remove this function, it is considered <loc href="#at-risk">at risk</loc>.
            </p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   

   <fos:function name="sort" prefix="array">
      <fos:signatures>
         <fos:proto name="sort" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="navigation"/>
            <fos:arg name="collation" type="xs:string?" usage="absorption" default="fn:default-collation()" note="default-on-empty"/>
            <fos:arg name="key" type="fn(item()*) as xs:anyAtomicType*" usage="inspection" default="fn:data#1" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
 

      <fos:summary>
         <p>Sorts a supplied array, based on the value of a sort key supplied as a function.</p>
      </fos:summary>
      <fos:rules>
         <p>This function is retained for compatibility from version 3.1 of this specification. Version 4.0
         introduces a more powerful functions, <function>array:sort-by</function>.</p>
         
         <p>The function call <code>array:sort($array, $collation, $key)</code> is defined to have the same effect as the
         call <code>array:sort-by($array, { 'key': $key, 'collation': $collation, 'order': 'ascending'})</code>.
         See <function>array:sort-by</function>.</p>
         
         <p>The result of the function is a sequence that contains all the items from <code>$input</code>,
         typically in a different order, the order being defined by the supplied sort key definitions.</p>
         
 
      </fos:rules>
      <fos:equivalent style="xpath-expression">
         array:sort-by($array, { 'key': $key, 'collation': $collation, 'order': 'ascending' })
      </fos:equivalent>
      <fos:errors>
         <p>If the set of computed sort keys contains values that are not comparable using the <code>lt</code> operator then the sort 
            operation will fail with a type error (<xerrorref
               spec="XP" class="TY" code="0004"/>).
         </p>
      </fos:errors>
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression>array:sort([ 1, 4, 6, 5, 3 ])</fos:expression>
               <fos:result>[ 1, 3, 4, 5, 6 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:sort([ 1, -2, 5, 10, -10, 10, 8 ], (), abs#1)</fos:expression>
               <fos:result>[ 1, -2, 5, 8, 10, -10, 10 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:sort([ [ 2, "i" ], [ 1, "e" ], [ 2, "g" ], [ 1, "f" ] ])</fos:expression>
               <fos:result>[ [ 1, "e" ], [ 1, "f" ], [ 2, "g" ], [ 2, "i" ] ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   
   <fos:function name="sort-by" prefix="array">
      <fos:signatures>
         <fos:proto name="sort-by" return-type="array(*)">
            <fos:arg name="array" type="array(*)" usage="navigation"/>
            <fos:arg name="keys" type="record(key? as (fn(item()*) as xs:anyAtomicType*)?, collation? as xs:string?, order? as enum('ascending', 'descending')?)*"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
 

      <fos:summary>
         <p>Sorts a supplied array, based on the value of a number of sort keys supplied as functions.</p>
      </fos:summary>
      <fos:rules>
         <p>The result of the function is an array that contains the same members as <code>$array</code>,
         typically in a different order, the order being defined by the supplied <term>sort key definitions</term>.</p>
         
         <p>A <term>sort key definition</term> is a record with three parts:</p>
         
         <olist>
            <item><p><code>key:</code> A <term>sort key function</term>, which is applied to each member of the input sequence to
            determine a <term>sort key value</term>. If no function is supplied, the default is <code>fn:data#1</code>,
            which atomizes the value of the array member.</p></item>
            <item><p><code>collation:</code> A <term>collation</term>, which is used when comparing <term>sort key values</term>
               that are of type <code>xs:string</code> or <code>xs:untypedAtomic</code>. If no collation is supplied, the default
               collation from the static context is used.</p>
               <p>When comparing values of types other than <code>xs:string</code> or <code>xs:untypedAtomic</code>,
               the collation is ignored (but an error <rfc2119>may</rfc2119> be reported if it is
               invalid). For more information see <specref ref="choosing-a-collation"/>.</p>
            
            </item>
            <item><p><code>order:</code> An <term>order direction</term>, either <code>"ascending"</code> or
            <code>"descending"</code>. The default is <code>"ascending"</code>.</p></item>
         </olist>
         
         <p>The number of sort key definitions is determined by the number of records supplied
            in the <code>$keys</code> argument. If the argument is absent or empty, the default is
            a single sort key definition using the function <code>data#1</code>, using the default collation
            from the static context, and with order <code>ascending</code>.</p>
         
        
         
        
         <p>The result of the <code>array:sort-by</code> function is obtained as follows:</p>
         
         <olist>
            <item>
               <p>The result array contains the same members as <code>$array</code>, 
                  but generally in a different order.</p>
            </item>
            <item>
               <p>The sort key definitions are established as described above.
                  The sort key definitions are in major-to-minor order. That is, the position of two
                  values <code>$A</code> and <code>$B</code> in the result sequence is determined first by the 
                  relative magnitude of their
                  primary sort key values, which are computed by evaluating the <term>sort key function</term> in the 
                  first sort key definition.
                  If those two sort key values are equal, then the position is determined by the relative magnitude
                  of their secondary sort key values, computed by evaluating the 
                  sort key function in the second sort key definition, and so on.</p>              
            </item>
            <item>
               <p>When a pair of corresponding sort key values of <code>$A</code> and <code>$B</code> are 
                  found to be not equal,
                  then <code>$A</code> precedes <code>$B</code> in the result sequence 
                  if both the following conditions are true, or if both conditions are false:</p>
                  <olist>
                     <item>
                        <p>The sort key value for <code>$A</code> is less than the sort key value for <code>$B</code>,
                           as defined below.</p>
                     </item>
                     <item>
                        <p>The <term>order direction</term> in the corresponding sort key definition
                        is <code>"ascending"</code>.</p>
                     </item>
                  </olist>
            </item>
            <item><p>If all the sort key values for <code>$A</code> and <code>$B</code> are pairwise equal, then 
               <code>$A</code> precedes <code>$B</code> in the result sequence if and only if
               <code>$A</code> precedes <code>$B</code> in the input sequence.</p>
               <note><p>That is, the sort is <emph>stable</emph>.</p></note>
            </item>
            <item>
               <p>Each sort key value for a given array member is obtained by applying the sort key
               function of the corresponding sort key definition to that member. The result
               of this function is in the general case a sequence of atomic items.
               Two sort key values <code>$a</code> and <code>$b</code> are compared as follows:</p>
               <olist>
                  <item><p>Let <var>$C</var> be the collation in the corresponding
                     sort key definition.</p>
                  </item>
                  <item><p>Let <code>$REL</code> be the result of evaluating <code>op:lexicographic-compare($key($A), $key($B), $C)</code>
                     where <code>op:lexicographic-compare($a, $b, $C)</code> is defined as follows:</p>
                     <eg>if (empty($a) and empty($b)) then 0 
else if (empty($a)) then -1
else if (empty($b)) then +1
else let $rel = op:simple-compare(head($a), head($b), $C)
     return if ($rel eq 0)
            then op:lexicographic-compare(tail($a), tail($b), $C)
            else $rel</eg></item>
                  <item><p>Here <code>op:simple-compare($k1, $k2)</code> is defined as follows:</p>
                     <eg>if ($k1 instance of (xs:string | xs:anyURI | xs:untypedAtomic)
    and $k2 instance of (xs:string | xs:anyURI | xs:untypedAtomic))
then compare($k1, $k2, $C)
else if ($k1 instance of xs:numeric and $k2 instance of xs:numeric)
then compare($k1, $k2)
else if ($k1 eq $k2) then 0
else if ($k2 lt $k2) then -1
else +1</eg>
                     <note><p>This raises an error if two keys are not comparable, for example
                        if one is a string and the other is a number, or if both belong to a non-ordered
                        type such as <code>xs:QName</code>.</p></note></item>
                  <item><p>If <code>$REL</code> is zero, then the two sort key values are deemed
                     equal; if <code>$REL</code> is -1 then <code>$a</code> is deemed less than
                     <code>$b</code>, and if <code>$REL</code> is +1 then <code>$a</code> is deemed greater than
                     <code>$b</code></p></item>
               </olist>
            </item>
         </olist>
      </fos:rules>
                  <fos:equivalent style="xpath-expression"><![CDATA[
$array
=> array:members()
=> fn:sort-by(
  for $key-spec in ($keys otherwise {})
  return map:put($key-spec, 'key', fn($member as record(value)) as xs:anyAtomicType* {
    map:get($key-spec, 'key', fn:data#1)(map:get($member, 'value'))
  }
)
=> array:of-members()
       ]]></fos:equivalent>
      <fos:errors>
         <p>If the set of computed sort keys contains values that are not comparable using the <code>lt</code> operator then the sort 
            operation will fail with a type error (<xerrorref
               spec="XP" class="TY" code="0004"/>).
         </p>
      </fos:errors>
      <fos:notes>
         <p>The function is a generalization of the <function>array:sort</function> function available in 3.1, 
            which is retained for compatibility. The enhancements allow multiple sort keys to be defined, each potentially with
         a different collation, and allow sorting in descending order.</p>
         <p>If the sort key for an item evaluates to the empty sequence, the effect of the rules is that this item
            precedes any value for which the key is non-empty. This is equivalent to the effect of the XQuery option 
            <code>empty least</code>. The effect of the option <code>empty greatest</code> can be achieved by adding an
            extra sort key definition with <code>{'key': fn{empty(K(.)}}</code>: when comparing boolean sort keys,
            <code>false</code> precedes <code>true</code>.</p>
      </fos:notes>
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression>array:sort-by([1, 4, 6, 5, 3], {})</fos:expression>
               <fos:result>[1, 3, 4, 5, 6]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:sort-by([1, 4, 4e0, 6, 5, 3], {'order': 'descending'})</fos:expression>
               <fos:result>[6, 5, 4, 4e0, 3, 1]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:sort-by([(1,4,3), 4, (5,6), 2], ({'key': count#1}, {}))</fos:expression>
               <fos:result>[2, 4, (5,6), (1,4,3)]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="1085" PR="2001" date="2025-05-19"><p>New in 4.0.</p></fos:change>
      </fos:changes>
   </fos:function>
   
   
   <fos:function name="sort-with" prefix="array">
      <fos:signatures>
         <fos:proto name="sort-with" return-type="array(*)">
            <fos:arg name="array" type="array(*)"/>
            <fos:arg name="comparators" type="(fn(item()*, item()*) as xs:integer)+"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Sorts a supplied array, according to the order induced by the supplied comparator
            functions.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the members of the supplied <code>$array</code> are sorted into an
            order based on the result of evaluating the supplied <code>$comparators</code>. 
            The result is a sorted array.</p>
         <p>Each comparator function takes two values and returns an <code>xs:integer</code> that
            defines the relationship between these values, following the conventions of the
            <function>fn:compare</function> function. Specifically, when a comparator
            <code>$c</code> is used to compare two values <code>$a</code> and <code>$b</code>,
            it must return a negative integer if <code>$a</code> is to be sorted before <code>$b</code>,
            zero if they are considered equal, and a positive integer if <code>$a</code> is
            to be sorted after <code>$b</code>.</p>
         
         <p>There may be more than one comparator, representing sort keys in major to minor order.
         To determine the relative position of two members <code>$a</code> and <code>$b</code>:</p>
         <olist>
            <item><p>The first comparator is called: <code>$comparators[1]($a, $b)</code>. If
            the result is non-zero, this determines the relative position of <code>$a</code>
               and <code>$b</code> in the result array, and any further comparators
            can be ignored.</p></item>
            <item><p>If the <var>N</var>th comparator returns zero, then:</p>
               <olist>
                  <item><p>If this is the last comparator, then the two members are considered
                  equal, and their relative position in the result sequence will be the same
                  as their relative position in the input sequence (that is, the sort is
                  <emph>stable</emph>).</p></item>
                  <item><p>Otherwise, the next comparator is evaluated, and so on,
                  until the last comparator is reached or the result of a comparator is non-zero.</p></item>
               </olist>
            </item>
            
         </olist>
         <p>To ensure that the sorting algorithm produces predictable results (indeed, to ensure
         that it terminates), it is necessary for the comparators to have certain properties.
         Specifically, for every comparator <var>C</var>:</p>
         
         <olist>
            <item><p><var>C</var> must be deterministic (if called twice with the same arguments,
            it must deliver the same result).</p></item>
            <item><p>Every value must be equal to itself: <code><var>C</var>($a, $a)</code> must be zero.</p></item>
            <item><p>The ordering must be consistent: if <code><var>C</var>($a, $b) &lt; 0</code>,
            then <code><var>C</var>($b, $a) &gt; 0</code>, and vice versa, and similarly,
            if <code><var>C</var>($a, $b) = 0</code>,
            then <code><var>C</var>($b, $a) = 0</code>.</p></item>
            <item><p>The ordering must be transitive: if <code><var>C</var>($a, $b) &lt; 0</code>
               and <code><var>C</var>($b, $c) &lt; 0</code>, then <code><var>C</var>($a, $c) &lt; 0</code>.</p></item>
         </olist>
         
  
         
 
         
      </fos:rules>
      
      <fos:errors>
         <p>If a comparator function raises an error when processing any pair of members from the input array
         (for example, if the comparator function is <code>fn:compare#2</code> and one of the members
            is not coercible to <code>xs:anyAtomicType</code>), then the evaluation of
            <function>fn:sort-with</function> fails with that error.</p> 
         
         <p>In general it is unpredictable which pairs of members from the input array
         will actually be compared using each comparator function. However, a comparator function
         <rfc2119>must</rfc2119> not be called to compare two members if they have been determined as unequal by
         an earlier comparator function.</p>
      </fos:errors>

      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:sort-with([1, 4, 6, 5, 3], compare#2)</fos:expression>
               <fos:result>[1, 3, 4, 5, 6]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:sort-with([1, 4, 6, 5, 3], op('-'))</fos:expression>
               <fos:result>[1, 3, 4, 5, 6]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:sort-with([1, 4, 4e0, 6, 5, 3], fn($a, $b) { compare($b, $a) })</fos:expression>
               <fos:result>[6, 5, 4, 4e0, 3, 1]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>array:sort-with(
  [ { "a": 1, "b": 20 }, { "a": 5, "b": 12 }, { "a": 1, "b": 3 } ],
   ( fn($x, $y) { compare($x?a, $y?a) },
     fn($x, $y) { compare($x?b, $y?b) })  
)</eg></fos:expression>
               <fos:result>[ { "a": 1, "b": 3 }, { "a": 1, "b": 20 }, { "a": 5, "b": 12 } ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="2012" PR="2228" date="2025-10-03"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
      

   <fos:function name="flatten" prefix="array">
      <fos:signatures>
         <fos:proto name="flatten" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="transmission"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Replaces any array appearing in a supplied sequence with the members of the array, recursively.</p>
      </fos:summary>
      <fos:rules>
         <p>The function processes the items in the supplied sequence <code>$input</code> as follows:</p>
         <ulist>
            <item>
               <p>An item that is an array is replaced by its members, retaining order.</p>
            </item>
            <item>
               <p>Any other item is retained unchanged.</p>
            </item>
         </ulist>
         <p>The process is then repeated so long as the sequence contains an array among its items.</p>
         <!--<p>The function is equivalent to the following implementation in XQuery:</p>
         <eg><![CDATA[
declare function flatten(
  $input as item()*
) as item()* {
  for $item in $input
  return if ($item instance of array(*)) then flatten(array:items($item)) else $item
};]]></eg>-->
      </fos:rules>
      <fos:equivalent style="xquery-function"><![CDATA[
declare function array:flatten(
  $input as item()*
) as item()* {
  for $item in $input
  return (
    if ($item instance of array(*)) 
    then array:flatten(array:items($item)) 
    else $item
  )
};
       ]]></fos:equivalent>
      <fos:notes>
         <p>The argument to the function will often be a single array item, but this is not essential.</p>
         <p>Unlike atomization, this function retains any nodes contained in the array.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:flatten([ 1, 4, 6, 5, 3 ])</fos:expression>
               <fos:result>1, 4, 6, 5, 3</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:flatten(([ 1, 2 ], [ [ 10, 11 ], 12 ], [], 13))</fos:expression>
               <fos:result>1, 2, 10, 11, 12, 13</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:flatten([ (1, 0), (1, 1), (0, 1), (0, 0) ])</fos:expression>
               <fos:result>1, 0, 1, 1, 0, 1, 0, 0</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
   </fos:function>
   <fos:function name="items" prefix="array">
      <fos:signatures>
         <fos:proto name="items" return-type="item()*">
            <fos:arg name="array" type="array(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the sequence concatenation of the members of an array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns the <xtermref spec="XP40" ref="dt-sequence-concatenation">sequence concatenation</xtermref> 
            of the members of <code>$array</code>, retaining order.</p>
        

      </fos:rules>
      <fos:equivalent style="xpath-expression">
         dm:iterate-array($array, fn($member, $pos) { $member })
      </fos:equivalent>
      <fos:notes>
         <p>Unlike <function>array:flatten</function>, the function does not apply recursively
         to nested arrays.</p>
         <p>If <code>$A</code> is a single array item, then <code>array:items($A)</code>
         returns the same result as <code>$A?*</code>.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>array:items(["one", "two", "three"])</fos:expression>
               <fos:result>"one", "two", "three"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:items(["one", ("two", "three")])</fos:expression>
               <fos:result>"one", "two", "three"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:items(["one", ("two", "three"), ()])</fos:expression>
               <fos:result>"one", "two", "three"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:items(["one", ["two", "three"]])</fos:expression>
               <fos:result>"one", ["two", "three"]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>array:items([ (), 1, (2 to 4), [ 5 ] ])</fos:expression>
               <fos:result>1, 2, 3, 4, [ 5 ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="29 1086" PR="476 1087" date="2023-09-05"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
 
   <fos:function name="load-xquery-module" prefix="fn">
      <fos:signatures>
         <fos:proto name="load-xquery-module" return-type-ref="load-xquery-module-record">
            <fos:arg name="module-uri" type="xs:string"/>
            <fos:arg name="options" type="map(*)?" usage="inspection" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-dependent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Provides access to the public functions and global variables of a dynamically loaded XQuery library module.</p>
      </fos:summary>
      <fos:rules>
         <p>The function loads an implementation-defined set of modules having the target namespace <code>$module-uri</code>.</p>
         <p>The <code>$options</code> argument can be used to control the way in which the function operates. 
            The <termref
               def="option-parameter-conventions">option parameter conventions</termref> apply.</p>
         
         <p>If the query module is retrieved as an external resource, this is subject to
         the <xtermref spec="XP40" ref="dt-trusted">trust level</xtermref> of the
         calling code. In addition, the ability of the loaded query module to access
         additional resources is subject to the value of the supplied <code>trusted</code>
         option.</p>
         
         <note>
            <p>Versions of XQuery prior to 4.0 do not define any constraints on access to
            external resources. Many XQuery implementations, however, provide such
            mechanisms. An implementation of <code>fn:load-xquery-module</code> that allows
            execution of an <xtermref spec="XP40" ref="dt-untrusted">untrusted</xtermref>
            query <rfc2119>must</rfc2119> ensure that the ability of that query to access resources
            is appropriately restricted, regardless of the version of XQuery in use.</p>
         </note>

         <fos:options>
            <fos:option key="xquery-version">
               <fos:meaning>The minimum level of the XQuery language that the
                  processor must support. </fos:meaning>
               <fos:type>xs:decimal</fos:type>
               <fos:default-description>The version given in the prolog of the library module; or
                  <termref
                     def="implementation-defined"
                  >implementation-defined</termref> if this is absent.</fos:default-description>
            </fos:option>
            <fos:option key="trusted">
               <fos:meaning>Indicates whether the returned query module is 
                  trusted to access external resources. This applies both to resources
               statically referenced in the query module (such as imported schemas and
               imported library modules), and to resources accessed dynamically by
               invoking functions in the retrieved module, for example by use of the
               <function>fn:doc</function> function.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false()</fos:default>
               <fos:values>
                  <fos:value value="true">The loaded query has the same level of trust
                     as the caller, and may therefore access all external resources
                     available to the caller.
                  </fos:value>
                  <fos:value value="false">The functions and variables in the returned
                     XQuery module are <xtermref spec="XP40" ref="dt-untrusted">untrusted</xtermref>, and
                     are therefore unable to access external resources unless these have been made
                     explicitly available by a trusted caller.
                  </fos:value>
               </fos:values>
            </fos:option>
            <fos:option key="location-hints">
               <fos:meaning>A sequence of URIs (in the form of <code>xs:string</code> values) which may be used or ignored in an
                  <termref
                     def="implementation-defined"
                  >implementation-defined</termref> way.</fos:meaning>
               <fos:type>xs:string*</fos:type>
               <fos:default>Empty sequence</fos:default>
            </fos:option>
            <fos:option key="content">
               <fos:meaning>The content of the query module as a string. When this option is used, the 
                  <code>location-hints</code> option is ignored. The static base URI of the dynamically loaded
                  module is the same as the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> 
                  of the caller.</fos:meaning>
               <fos:type>xs:string?</fos:type>
               <fos:default>Empty sequence</fos:default>
            </fos:option>
            <fos:option key="context-item">
               <fos:meaning>The item to be used as the initial context item when evaluating global variables in the library module. Supplying
                  the empty sequence is equivalent to omitting the entry from the map, and indicates the absence of a context item.
                  If the library module specifies a required type for the context item, then the supplied value <rfc2119>must</rfc2119> conform to
                  this type, without conversion.</fos:meaning>
               <fos:type>item()?</fos:type>
               <fos:default>Absent</fos:default>
            </fos:option>
            <fos:option key="variables">
               <fos:meaning>Values for external variables defined in the library module. Values <rfc2119>must</rfc2119> be supplied
                  for external variables that have no default value, and <rfc2119>may</rfc2119> be supplied for external variables
                  that do have a default value. The supplied value <rfc2119>must</rfc2119> conform to the required type of the variable, without conversion.
                  The map contains one entry for each external variable: the key is the variable’s name, and the associated value is
                  the variable’s value. The <termref
                     def="option-parameter-conventions"
                  >option parameter conventions</termref> do not apply
                  to this contained map.</fos:meaning>
               <fos:type>map(xs:QName, item()*)</fos:type>
               <fos:default>The empty map</fos:default>
            </fos:option>
            <fos:option key="vendor-options">
               <fos:meaning>Values for vendor-defined configuration options for the XQuery processor used to process the request. The key is the
                  name of an option, expressed as a QName: the namespace URI of the QName <rfc2119>should</rfc2119> be a URI controlled
                  by the vendor of the XQuery processor. The meaning of the associated value is <termref
                     def="implementation-defined"
                     >implementation-defined</termref>.
                  Implementations <rfc2119>should</rfc2119> ignore options whose names are in an unrecognized namespace. 
                  The <termref
                     def="option-parameter-conventions"
                  >option parameter conventions</termref> do not apply
                  to this contained map.</fos:meaning>
               <fos:type>map(xs:QName, item()*)</fos:type>
               <fos:default>The empty map</fos:default>
            </fos:option>
         </fos:options>

  
         <p>The result of the function is a map
         <var>R</var> with two entries, as defined in <specref ref="load-xquery-module-record"/>.</p>

         
         <p>The static and dynamic context of the library module are established according to the rules in 
            <xspecref
               spec="XQ31" ref="id-xq-context-components"/>.</p>

         <p>It is <termref def="implementation-defined"
               >implementation-defined</termref> whether constructs in the library module 
            are evaluated in the same <termref
               def="execution-scope">execution scope</termref> as the calling module.</p>

         <p>The library module that is loaded may import other modules using an <code>import module</code> declaration. The result of
            <function>fn:load-xquery-module</function> does not include global variables or functions declared in such a transitively imported module.
            However, the <code>options</code> map supplied in the function call <rfc2119>may</rfc2119> 
            (and if no default is defined, <rfc2119>must</rfc2119>)
            supply values for external variables declared in transitively loaded library modules.</p>

         <p>The library module that is loaded may import schema declarations using an <code>import schema</code> declaration. It is
            <termref
               def="implementation-defined"
               >implementation-defined</termref> whether schema components in the in-scope 
            schema definitions of the calling module
            are automatically added to the in-scope schema definitions of the dynamically loaded module. The in-scope schema definitions
            of the calling and called modules must be consistent, according to the rules defined in 
            <xspecref
               spec="XQ31" ref="id-consistency-constraints"/>.</p>

         <p>Where nodes are passed to or from the dynamically loaded module, for example as an argument or result of a function, 
            they <rfc2119>should</rfc2119> if possible retain their node identity, their base URI, their type annotations, and their relationships to all other nodes 
            in the containing tree (including ancestors and siblings). If this is not possible, for example because the only way of passing nodes 
            to the chosen XQuery implementation is by serializing and re-parsing, then a node <rfc2119>may</rfc2119> be passed in the form of a deep 
            copy, which may lose information about the identity of the node, about its ancestors and siblings, about its base URI, about its type annotations, and about its 
            relationships to other nodes passed across the interface.</p>


      </fos:rules>
      <fos:errors>
         <p>If <code>$module-uri</code> is a zero length string, a dynamic error is raised <errorref
               class="QM" code="0001"/>.</p>
         <p>If the implementation is not able to find a library module with the specified target namespace, 
            an error is raised <errorref
               class="QM" code="0002"/>.</p>
         <p>If a static error (including a statically detected type error) is encountered when processing the library module, 
            a dynamic error is raised <errorref
               class="QM" code="0003"/>.</p>

         <p>If a value is supplied for the initial context item or for an external variable and the value does not conform to the required
            type declared in the dynamically loaded module, a dynamic error is raised <errorref
               class="QM" code="0005"/>.</p>
         <p>If no suitable XQuery processor is available, a dynamic error is raised <errorref
               class="QM" code="0006"
            />.
         This includes (but is not limited to) the following cases:</p>
         <olist>
            <item>
               <p>No XQuery processor is available;</p>
            </item>
            <item>
               <p>Use of the function has been disabled;</p>
            </item>
            <item>
               <p>No XQuery processor supporting the requested version of XQuery is available;</p>
            </item>
            <item>
               <p>No XQuery processor supporting the optional Module Feature is available.</p>
            </item>
         </olist>

         <p>If a dynamic error (including a dynamically detected type error) is encountered when processing the module 
            (for example, when evaluating its global variables), the dynamic error is returned <emph>as is</emph>.</p>
      </fos:errors>

      <fos:notes>
         
         <p>If a function declaration <var>F</var> in the loaded module declares (say) four parameters of which one is optional,
            its arity range will be from 3 to 4, so the result will include two function items corresponding to <code>F#3</code>
            and <code>F#4</code>. In the lower-arity function item, <code>F#3</code>, the fourth parameter will take its
            default value. If the expression that initializes the default value is context sensitive, the static and dynamic
            context for its evaluation are the static and dynamic contexts of the <function>fn:load-xquery-module</function>
            function call itself.
         </p>
         
         <p>As with all other functions in this specification, conformance requirements depend on the host language.
         For example, a host language might specify that provision of this function is optional, or that it is excluded entirely,
         or that implementations are required to support XQuery modules using a specified version of XQuery.</p>

         <p>Even where support for this function is mandatory, it is <rfc2119>recommended</rfc2119> for security reasons that implementations
         should provide a user option to disable its use, or to disable aspects of its functionality.</p>
         
         <p diff="add" at="issue725">The <code>load-xquery-module</code> function does not modify the static or dynamic context.
         Functions and variables from the loaded module become available within the result returned by the function, but they
         are not added to the static or dynamic context of the caller. This means, for example, that <code>function-lookup</code>
         will not locate functions from the loaded module.</p>
         
         
      </fos:notes>
      <fos:examples>
         <fos:example>
         <fos:test>
            <fos:expression><eg>let $expr := "2 + 2"
let $module := `
  xquery version "4.0"; 
  module namespace dyn="http://example.com/dyn";
  declare %public variable $dyn:value := { $expr };
`
let $exec := load-xquery-module(
  "http://example.com/dyn",
  { 'content':$module }
)
let $variables := $exec?variables
return $variables( #Q{http://example.com/dyn}value )</eg></fos:expression>
            <fos:result>4</fos:result>
         </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="725" PR="727" date="2023-10-10">
            <p>It has been clarified that loading a module has no effect on the static or dynamic context
               of the caller.</p>
         </fos:change>
         <fos:change issue="883" PR="1072" date="2024-03-19">
            <p>The return type is now specified more precisely.</p>
         </fos:change>
         <fos:change issue="1329" PR="1333" date="2024-07-22">
            <p>A new option is provided to allow the content of the loaded module to be supplied as a string.</p>
         </fos:change>
      </fos:changes>
      
   </fos:function>

   <fos:function name="transform" prefix="fn">
      <fos:signatures>
         <fos:proto name="transform" return-type="map(*)">
            <fos:arg name="options" type="map(*)" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Invokes a transformation using a dynamically loaded XSLT stylesheet.</p>
      </fos:summary>
      <fos:rules>
         <p>This function loads an XSLT stylesheet and invokes it to perform a transformation.</p>
         <p>The inputs to the transformation are supplied in the form of a map. 
            The <termref
               def="option-parameter-conventions"
            >option parameter conventions</termref> apply
            to this map; they do not apply to any nested map unless otherwise specified.</p>

         <p>The function first identifies the <term>requested XSLT version</term>, as follows:</p>

         <ulist>
            <item>
               <p>If the <code>xslt-version</code>
               option is present, the requested XSLT version is the value of that option. </p>
            </item>
            <item>
               <p>Otherwise, the requested XSLT version
               is the value of the <code>[xsl:]version</code> attribute of the outermost element in the supplied stylesheet or package.</p>
            </item>
         </ulist>

         <p>The function then attempts to locate an XSLT processor that implements the requested XSLT version.</p>

         <ulist>
            <item>
               <p>If a processor that implements the requested XSLT version is available, then it is used. </p>
            </item>
            <item>
               <p>Otherwise, if a processor that implements a version later than the requested version is available, then it is used. </p>
            </item>
            <item>
               <p>Otherwise, the function fails indicating that no suitable XSLT processor is available.</p>
            </item>
         </ulist>

         <note>
            <p>The phrase <emph>locate an XSLT processor</emph> includes the possibility of locating a software product and
         configuring it to act as an XSLT processor that implements the requested XSLT version.</p>
         </note>

         <p>If more than one XSLT processor is available under the above rules, then the one that is chosen may be selected according to
         the availability of requested features: see below.</p>

         <p>Once an XSLT processor has been selected that implements a given version of XSLT, the processor
         follows the rules of that version of the XSLT specification. This includes any decision to operate in backwards or forwards
         compatibility mode. For example, if an XSLT 2.0 processor is selected, and the stylesheet specifies <code>version="1.0"</code>,
         then the processor will operate in backwards compatibility mode; if the same processor is selected and the stylesheet
         specifies <code>version="3.0"</code>, the processor will operate in forwards compatibility mode.</p>

         <p>If the stylesheet to be executed is retrieved as an external resource, this is subject to
         the <xtermref spec="XP40" ref="dt-trusted">trust level</xtermref> of the
         calling code. In addition, the ability of the loaded stylesheet to access
         additional resources is subject to the value of the supplied <code>trusted</code>
         option.</p>
         
         <note>
            <p>Versions of XSLT prior to 4.0 do not define any constraints on access to
            external resources. Many XSLT implementations, however, provide such
            mechanisms. An implementation of <code>fn:transform</code> that allows
            an XSLT processor to execute an <xtermref spec="XP40" ref="dt-untrusted">untrusted</xtermref>
            stylesheet <rfc2119>must</rfc2119> ensure that the ability of that stylesheet to access resources
            is appropriately restricted, regardless of the version of XSLT.</p>
         </note>

         <p>The combinations of options that are relevant to each version of XSLT, other than <code>xslt-version</code> 
            itself, are listed below. This is followed by a table giving the meaning of each option.</p>



         <olist>
            <item>
               <p>For invocation of an XSLT 1.0 processor (see <bibref ref="xslt10"
                     />), 
                  the supplied options must include all of the following <phrase
                     diff="chg" at="E">(if anything else is present, it is ignored)</phrase>:</p>
               <olist>
                  <item>
                     <p>The stylesheet, provided by supplying exactly one of the following:</p>
                     <slist>
                        <sitem>
                           <code>stylesheet-location</code>
                        </sitem>
                        <sitem>
                           <code>stylesheet-node</code>
                        </sitem>
                        <sitem>
                           <code>stylesheet-text</code>
                        </sitem>
                     </slist>
                  </item>
                  <item>
                     <p>The source tree, provided as the value of the <code>source-node</code> option.</p>
                  </item>
                  <item>
                     <p>Zero or more of the following additional options:</p>
                     <slist>
                        <sitem>
                           <code>stylesheet-base-uri</code>
                        </sitem>
                        <sitem><code>stylesheet-params</code> (defaults to the empty map)</sitem>
                        <sitem><code>initial-mode</code> (defaults to the stylesheet’s default mode)</sitem>
                        <sitem><code>delivery-format</code> (defaults to <code>document</code>)</sitem>
                        <sitem><code>serialization-params</code> (defaults to the empty map)</sitem>
                        <sitem><code>enable-messages</code> (default is implementation-defined)</sitem>
                        <sitem><code>requested-properties</code> (default is the empty map)</sitem>
                        <sitem><code>trusted</code> (default is <code>false</code>)</sitem>
                        <sitem><code>vendor-options</code> (defaults to the empty map)</sitem>
                        <sitem><code>cache</code> (default is implementation-defined)</sitem>
                     </slist>
                  </item>
               </olist>
            </item>
            <item>
               <p>For invocation of an XSLT 2.0 processor (see <bibref ref="xslt20"
                     />), 
                  the supplied options must include all of the following <phrase
                     diff="chg" at="E">(if anything else is present, it is ignored)</phrase>:</p>
               <olist>
                  <item>
                     <p>The stylesheet, provided by supplying exactly one of the following:</p>
                     <slist>
                        <sitem>
                           <code>stylesheet-location</code>
                        </sitem>
                        <sitem>
                           <code>stylesheet-node</code>
                        </sitem>
                        <sitem>
                           <code>stylesheet-text</code>
                        </sitem>
                     </slist>
                  </item>
                  <item>
                     <p>Invocation details, as exactly one of the following:</p>
                     <olist>
                        <item>
                           <p>For apply-templates invocation, all of the following:</p>
                           <p>
                              <code>source-node</code>
                           </p>
                           <p>Optionally, <code>initial-mode</code> (defaults to the stylesheet’s default mode)</p>
                        </item>
                        <item>
                           <p>For call-template invocation, all of the following:</p>
                           <p>
                              <code>initial-template</code>
                           </p>
                           <p>Optionally, <code>source-node</code></p>
                        </item>
                     </olist>
                  </item>
                  <item>
                     <p>Zero or more of the following additional options:</p>
                     <slist>
                        <sitem>
                           <code>stylesheet-base-uri</code>
                        </sitem>
                        <sitem><code>stylesheet-params</code> (defaults to the empty map)</sitem>
                        <sitem><code>base-output-uri</code> (defaults to absent)</sitem>
                        <sitem><code>delivery-format</code> (defaults to <code>document</code>)</sitem>
                        <sitem><code>serialization-params</code> (defaults to the empty map)</sitem>
                        <sitem><code>enable-messages</code> (default is implementation-defined)</sitem>
                        <sitem><code>enable-trace</code> (default is implementation-defined)</sitem>
                        <sitem><code>requested-properties</code> (default is the empty map)</sitem>
                        <sitem><code>trusted</code> (default is <code>false</code>)</sitem>
                        <sitem><code>vendor-options</code> (defaults to the empty map)</sitem>
                        <sitem><code>cache</code> (default is implementation-defined)</sitem>
                     </slist>
                  </item>
               </olist>
            </item>
            <item>

               <p>For invocation of an XSLT 3.0 or XSLT 4.0 processor (see <bibref ref="xslt-40"
                     />), 
                  the supplied options must include all of the following <phrase
                     diff="chg" at="E">(if anything else is present, it is ignored)</phrase>:</p>
               <olist>
                  <item>
                     <p>The stylesheet, provided either by supplying exactly one of the following:</p>
                     <slist>
                        <sitem>
                           <code>stylesheet-location</code>
                        </sitem>
                        <sitem>
                           <code>stylesheet-node</code>
                        </sitem>
                        <sitem>
                           <code>stylesheet-text</code>
                        </sitem>
                     </slist>

                     <p>Or by supplying exactly one of the following:</p>
                     <slist>
                        <sitem>
                           <code>package-location</code>
                        </sitem>
                        <sitem>
                           <code>package-node</code>
                        </sitem>
                        <sitem>
                           <code>package-text</code>
                        </sitem>
                        <sitem><code>package-name</code> plus optionally <code>package-version</code></sitem>
                     </slist>
                  </item>
                  <item>
                     <p>Invocation details, as exactly one of the following combinations:</p>
                     <olist>
                        <item>
                           <p>For apply-templates invocation, all of the following:</p>
                           <p>Exactly one of <code>source-node</code>, <code>source-location</code>,
                              or <code>initial-match-selection</code></p>
                           <p>Optionally, <code>initial-mode</code></p>
                           <p>Optionally, <code>template-params</code></p>
                           <p>Optionally, <code>tunnel-params</code></p>
                        </item>
                        <item>
                           <p>For call-template invocation using an explicit template name, all of the following:</p>
                           <p>
                              <code>initial-template</code>
                           </p>
                           <p>Optionally, <code>template-params</code></p>
                           <p>Optionally, <code>tunnel-params</code></p>
                           <p>Optionally, <code>source-node</code></p>
                        </item>
                        <item>
                           <p>For call-template invocation using the defaulted template name <code>xsl:initial-template</code>, all of the following:</p>
                           <p>Optionally, <code>template-params</code></p>
                           <p>Optionally, <code>tunnel-params</code></p>
                           <note>
                              <p>If the <code>source-node</code> or <code>source-location</code>option 
                                 is present and <code>initial-template</code> is absent,
                              then apply-templates invocation will be used. To use call-template invocation on the template
                              named <code>xsl:initial-template</code> while also supplying a context item for use when evaluating
                              global variables, either (a) supply the context item using the <code>global-context-item</code> option,
                              or (b) supply <code>source-node</code>, and set the <code>initial-template</code> option explicitly to the 
                              QName <code>xsl:initial-template</code></p>
                           </note>
                        </item>
                        <item>
                           <p>For call-function invocation, all of the following:</p>
                           <p>
                              <code>initial-function</code>
                           </p>
                           <p>
                              <code>function-params</code>
                           </p>
                        </item>
                     </olist>
                     <note>
                        <p>The invocation method can be determined as the first of the following which applies:</p>
                        <ulist>
                           <item>
                              <p>If <code>initial-function</code> is present, then call-function invocation.</p>
                           </item>
                           <item>
                              <p>If <code>initial-template</code> is present, then call-template invocation.</p>
                           </item>
                           <item>
                              <p>If <code>source-node</code> or <code>source-location</code> 
                                 or <code>initial-match-selection</code>
                              is present, then apply-templates invocation.</p>
                           </item>
                           <item>
                              <p>Otherwise, <code>call-template</code> invocation using
                              the default entry point <code>xsl:initial-template</code>.</p>
                           </item>
                        </ulist>
                     </note>
                  </item>
                  <item>
                     <p>Zero or more of the following additional options:</p>
                     <slist>
                        <sitem>
                           <code>stylesheet-base-uri</code>
                        </sitem>
                        <sitem><code>static-params</code> (defaults to the empty map)</sitem>
                        <sitem><code>stylesheet-params</code> (defaults to the empty map)</sitem>
                        <sitem><code>global-context-item</code> (defaults to absent)</sitem>
                        <sitem><code>base-output-uri</code> (defaults to absent)</sitem>
                        <sitem>
                           <code>delivery-format</code>
                        </sitem>
                        <sitem><code>serialization-params</code> (defaults to the empty map)</sitem>
                        <sitem><code>enable-assertions</code> (default is <code>false</code>)</sitem>
                        <sitem><code>enable-messages</code> (default is implementation-defined)</sitem>
                        <sitem><code>enable-trace</code> (default is implementation-defined)</sitem>
                        <sitem><code>requested-properties</code> (default is the empty map)</sitem>
                        <sitem><code>trusted</code> (default is <code>false</code>)</sitem>
                        <sitem><code>vendor-options</code> (defaults to the empty map)</sitem>
                        <sitem><code>cache</code> (default is implementation-defined)</sitem>
                     </slist>
                  </item>
               </olist>
            </item>
         </olist>

         <p>The meanings of each option are defined in the table below.</p>

         <fos:options>

            <fos:option key="base-output-uri">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>The URI of the principal result document; also used as the base URI for
            resolving relative URIs of secondary result documents. If the value is a relative 

            reference, it is resolved against the 
                  <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> 
                  of the <code>fn:transform</code> 
                  function call. </fos:meaning>

               <fos:type>xs:string</fos:type>
               <fos:default-description>The effect of not
            supplying a base output URI is defined by the XSLT specification; the implementation

            <rfc2119>may</rfc2119> supply a default, for example the current working directory. 
               If the <code>fn:transform</code> function is called from XSLT, then
               the <rfc2119>recommended</rfc2119> default is the current output URI
               of the calling transformation.</fos:default-description>

            </fos:option>
            <fos:option key="cache">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>This option has no effect on the result of the transformation but may affect
            efficiency. The value <code>true</code> indicates an expectation that the same
            stylesheet is likely to be used for more than one transformation; the value
                <code>false</code> indicates an expectation that the stylesheet will be used once
            only.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>true</fos:default>
            </fos:option>
            <fos:option key="delivery-format">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>The manner in which the transformation results should be delivered. Applies both to the
            principal result document and to secondary result documents created using
                <code>xsl:result-document</code>.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>document</fos:default>
               <fos:default-description>If the relevant
            <code>xsl:output</code> or <code>xsl:result-document</code> element specifies
            <code>build-tree="no"</code> (applies to XSLT 3.0 only), then the default
            is <code>raw</code>.</fos:default-description>
               <fos:values>
                  <fos:value value="document"
                     >The result is delivered as a
                        document node.</fos:value>
                  <fos:value value="serialized"
                        >The result is delivered as
                        a string, representing the results of serialization. Note that (as with the
                            <function>fn:serialize</function> function) the final encoding stage of
                        serialization (which turns a sequence of characters into a sequence of
                        octets) is either skipped, or reversed by decoding the octet stream back
                        into a character stream.</fos:value>
                  <fos:value value="raw"
                     >The result of the initial
                template or function is returned as an arbitrary XDM value (after conversion
                to the declared type, but without wrapping in a document node, and without
                serialization): when this option is chosen, the returned map contains the
                raw result.</fos:value>
                  <fos:value value="file"
                     >The serialized result is written to persistent storage. This means that the
                  <code>fn:transform</code> function has side-effects and becomes nondeterministic,
                  so the option should be used with care, and the precise behavior may
                  be <termref def="implementation-defined"/>. When this option is used,
                  the URIs used for the <code>base-output-uri</code> and the URIs of any
                  secondary result documents must be writable locations.</fos:value>
               </fos:values>

            </fos:option>
            <fos:option key="enable-assertions">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>Indicates whether any <code>xsl:assert</code> instructions in the stylesheet
            are to be evaluated.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="enable-messages">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>Indicates whether any <code>xsl:message</code> instructions in the stylesheet
            are to be evaluated. The destination and formatting of any such messages is
            <termref def="implementation-defined"/>.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default-description><termref def="implementation-defined">Implementation-defined</termref>.</fos:default-description>
            </fos:option>
            <fos:option key="enable-trace">
               <fos:applies-to>2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>Indicates whether any <function>fn:trace</function> functions in the stylesheet are to
            generate diagnostic messages. The destination and formatting of any such messages is
            implementation-defined.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default-description><termref def="implementation-defined">Implementation-defined</termref>.</fos:default-description>
            </fos:option>
            <fos:option key="function-params">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>An array of values to be used as the arguments to the initial function call.
            The value is converted to the required type of the declared parameter using the function
            conversion rules.</fos:meaning>
               <fos:type>array(item()*)</fos:type>
               <fos:default>Empty array</fos:default>
            </fos:option>
            <fos:option key="global-context-item">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The value of the global context item, as defined in XSLT 3.0</fos:meaning>
               <fos:type>item()</fos:type>

               <fos:default-description>The value of <code>source-node</code>, if supplied</fos:default-description>

            </fos:option>
            <fos:option key="initial-function">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The name of the initial function to be called for call-function invocation. The
            arity of the function is inferred from the length of
            <code>function-params</code>.</fos:meaning>
               <fos:type>xs:QName</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="initial-match-selection">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The value of the initial match selection, as defined in XSLT 3.0</fos:meaning>
               <fos:type>item()*</fos:type>
               <fos:default-description>The value of <code>source-node</code></fos:default-description>
            </fos:option>
            <fos:option key="initial-mode">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>The name of the initial processing mode.</fos:meaning>
               <fos:type>xs:QName</fos:type>
               <fos:default-description>none</fos:default-description>
            </fos:option>
            <fos:option key="initial-template">
               <fos:applies-to>2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>The name of a named template in the stylesheet to act as the initial entry
            point.</fos:meaning>
               <fos:type>xs:QName</fos:type>
               <fos:default>xsl:initial-template</fos:default>
            </fos:option>
            <fos:option key="package-name">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The name of the top-level stylesheet package to be invoked (an absolute
            URI)</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="package-location">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The location of the top-level stylesheet package, as a relative or absolute
            URI</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="package-node">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>A document or element node containing the top-level stylesheet
            package</fos:meaning>
               <fos:type>node()</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="package-text">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The top-level stylesheet package in the form of unparsed lexical
            XML.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>

            <fos:option key="package-version">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The version of the top-level stylesheet package to be invoked.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default>"*" (any version)</fos:default>
            </fos:option>
            <fos:option key="post-process">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>A function that is used to post-process each result document of
                  the transformation (both the principal result and secondary results), in whatever
                  form it would otherwise be delivered (document, serialized, or raw). The first 

                  argument of the function is the key used to identify the result in the map return
                  by the <function>fn:transform</function> function (for example, this will be the supplied
                  base output URI in the case of the principal result, or the string “output” if no
                  base output URI was supplied). The second argument is the 
                  actual value. The value that is returned in the result of the <function>fn:transform</function> 
                  function is the result of applying this post-processing.
                  
                  <note>
                     <p>If the implementation provides a way of writing or invoking functions 
                        with side-effects, this post-processing function might be used to save 
                        a copy of the result document to persistent storage. For example, if the 
                        implementation provides access to the EXPath File library <bibref
                           ref="expath"
                           />, 
                        then a serialized document might be written to filestore by calling the 
                        <code>file:write</code> function. Similar mechanisms might be used to issue 
                        an HTTP POST request that posts the result to an HTTP server, or to send 
                        the document to an email recipient. The semantics of calling functions 
                        with side-effects are entirely <termref
                           def="implementation-defined">implementation-defined</termref>.</p>
                           <p>If the primary purpose of the post-processing function is achieved by 
                        means of such side-effects, and if the actual results are not needed by 
                        the caller of the <function>fn:transform</function> function, then it does not matter what 
                        the post-processing function actually returns (it could be the empty 
                        sequence, for example).</p>
                           <p>Calls to <function>fn:transform</function> can potentially have side-effects 
                        even in the absence of the post-processing option, because the XSLT 
                        specification allows a stylesheet to invoke extension functions 
                        that have side-effects. The semantics in this case are <termref
                           def="implementation-defined">implementation-defined</termref>.</p>
                  </note></fos:meaning>
               <fos:type>fn(xs:string, item()*) as item()*</fos:type>
               <fos:default>fn($a, $b) { $b }</fos:default>
            </fos:option>
            <fos:option key="requested-properties">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>The keys in the map are QNames that could legitimately be supplied in a call to
            the XSLT <code>system-property</code> function; the values in the map are the requested
            settings of the corresponding property. The boolean values <code>true</code> and
                <code>false</code> are equivalent to the string values <code>yes</code> and
                <code>no</code>. As a special case, setting a value for <code>xsl:version</code> has
            no effect, because of the potential for conflict with other options. For example: <ulist>
                     <item><p>Setting <code>xsl:product-name</code> to a particular value requests a
                        particular XSLT software product.</p></item>
                     <item><p>Setting <code>xsl:product-version</code> requests a specific version of
                        that product.</p></item>
                     <item><p>Setting <code>xsl:is-schema-aware</code> to <code>true</code> requests a
                        schema-aware processor.</p></item>
                     <item><p>Setting <code>xsl:xsd-version</code> to <code>"1.1"</code> requests a
                        processor that supports XML Schema version 1.1.</p></item>
                  </ulist> Setting a boolean property such as <code>xsl:supports-dynamic-evaluation</code>
            to <code>false</code> is interpreted as an explicit request for a processor in which
            the value of the property is <code>false</code>. The effect if the requests cannot be precisely met
            is implementation-defined. In some cases it may be appropriate to ignore the request or
            to provide an alternative (for example, a later version of the product than the one
            requested); in other cases it may be more appropriate to raise an error <errorref
                     class="XT" code="0001" type="dynamic"
                  /> indicating that no suitable XSLT processor
            is available. </fos:meaning>
               <fos:type>map(xs:QName, xs:anyAtomicType)</fos:type>
               <fos:default>Empty map</fos:default>
            </fos:option>
            <fos:option key="serialization-params">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>Serialization parameters for the principal result document. The supplied map
            follows the same rules that apply to a map supplied as the second argument of
                <function>fn:serialize</function>. <ulist>
                     <item><p>When a parameter is supplied, the corresponding value overrides or augments
                        the value specified in the unnamed <code>xsl:output</code> declaration (or
                        its default), following the same rules as when one <code>xsl:output</code>
                        declaration overrides another with lower import precedence.</p></item>
                     <item><p>When a parameter is supplied and the corresponding value is the empty
                        sequence (for example, <code>{ "standalone": () }</code>), any value
                        specified in the unnamed <code>xsl:output</code> declaration is overridden
                        by the default value. </p></item>
                     <item><p>When a parameter is not supplied in <code>serialization-params</code> (that
                        is, when the key is absent) the value that applies is the value appearing in
                        the unnamed <code>xsl:output</code> declaration, or its default. </p></item>
                  </ulist></fos:meaning>
               <fos:type>map(xs:anyAtomicType, item()*)</fos:type>
               <fos:default>Empty map</fos:default>
            </fos:option>
            
            <fos:option key="source-location">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>When <code>source-location</code> is supplied then 
                  it is expected to be an absolute or relative URI identifying an
                  unparsed XML document. If relative, it
                  is resolved against the static base URI of the <code>fn:transform</code> function call.
                  The document at this location is parsed,
                  and the document node acts as the
                  <code>initial-match-selection</code>, that is, stylesheet execution starts by
                  applying templates to this node. If the initial mode is streamable
                  and a streaming XSLT 3.0 or XSLT 4.0 processor is used,
                  then the supplied document is processed in streaming mode.</fos:meaning>
               <fos:type>node()</fos:type>
               <fos:default>n/a</fos:default>
            </fos:option>
            
            <fos:option key="source-node">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>When <code>source-node</code> is supplied then the
                <code>global-context-item</code> (the context item for evaluating global variables)
            is the root of the tree containing the supplied node. In addition, for apply-templates
            invocation, the <code>source-node</code> acts as the
                <code>initial-match-selection</code>, that is, stylesheet execution starts by
            applying templates to this node.</fos:meaning>
               <fos:type>node()</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>

            <fos:option key="static-params">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The values of static parameters defined in the stylesheet; the keys are the
            names of the parameters, and the associated values are their values. The value is
            converted to the required type of the declared parameter using the coercion
            rules.</fos:meaning>
               <fos:type>map(xs:QName, item()*)</fos:type>
               <fos:default>Empty map</fos:default>
            </fos:option>
            <fos:option key="stylesheet-base-uri">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>A string intended to be used as the static base URI of the principal stylesheet
            module. This value <rfc2119>must</rfc2119> be used if no other static base URI is
            available. If the supplied stylesheet already has a base URI (which will generally be
            the case if the stylesheet is supplied using <code>stylesheet-node</code> or
                <code>stylesheet-location</code>) then it is <termref
                     def="implementation-defined"
                     >implementation-defined</termref> whether this
            parameter has any effect. If the value is a relative reference, it is resolved against

            the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> 
                  of the <code>fn:transform</code> function call.</fos:meaning>

               <fos:type>xs:string</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="stylesheet-location">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>URI that can be used to locate the principal stylesheet module. If relative, it

            is resolved against the <xtermref spec="XP40" ref="dt-executable-base-uri">executable base URI</xtermref> 
                  of the <code>fn:transform</code> function call.

            The value also acts as the default for stylesheet-base-uri.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="stylesheet-node">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>Root of the tree containing the principal stylesheet module, as a document or
            element node. The base URI of the node acts as the default for
            stylesheet-base-uri.</fos:meaning>
               <fos:type>node()</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="stylesheet-params">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>A map holding values to be supplied for stylesheet parameters. The keys are the
            parameter names; the values are the corresponding parameter values. The values are
            converted if necessary to the required type using the coercion rules. The
            default is the empty map.</fos:meaning>
               <fos:type>map(xs:QName, item()*)</fos:type>
               <fos:default>Empty map</fos:default>
            </fos:option>

            <fos:option key="stylesheet-text">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>The principal stylesheet module in the form of unparsed lexical
            XML.</fos:meaning>
               <fos:type>xs:string</fos:type>
               <fos:default-description>n/a</fos:default-description>
            </fos:option>
            <fos:option key="template-params">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The values of non-tunnel parameters to be supplied to the initial template,
            used with both apply-templates and call-template invocation. Each value is converted to
            the required type of the declared parameter using the coercion
            rules.</fos:meaning>
               <fos:type>map(xs:QName, item()*)</fos:type>
               <fos:default-description>none</fos:default-description>
            </fos:option>
            <fos:option key="tunnel-params">
               <fos:applies-to>3.0, 4.0</fos:applies-to>
               <fos:meaning>The values of tunnel parameters to be supplied to the initial template, used
            with both apply-templates and call-template invocation. Each value is converted to the
            required type of the declared parameter using the coercion
            rules.</fos:meaning>
               <fos:type>map(xs:QName, item()*)</fos:type>
               <fos:default>Empty map</fos:default>
            </fos:option>
            
            <fos:option key="trusted">
               <fos:meaning>Indicates whether the target stylesheet is 
                  trusted to access external resources. This applies both to resources
               statically referenced by the stylesheet (for example using
               <code>xsl:include</code>, <code>xsl:import</code>, <code>xsl:use-package</code>,
                  or <code>xsl:import-schema</code>), and to resources accessed dynamically by
               executing the retrieved stylesheet, for example by use of the
               <function>fn:doc</function> or <function>unparsed-text</function> function.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false()</fos:default>
               <fos:values>
                  <fos:value value="true">The loaded stylesheet has the same level of trust
                     as the caller, and may therefore access all external resources
                     available to the caller.
                  </fos:value>
                  <fos:value value="false">The loaded stylesheet is <xtermref spec="XP40" ref="dt-untrusted">untrusted</xtermref>, and
                     is therefore unable to access external resources unless these have been made
                     explicitly available by a trusted caller.
                  </fos:value>
               </fos:values>
            </fos:option>

            <fos:option key="vendor-options">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>Values for vendor-defined configuration options for the XSLT processor used to
            process the request. The key is the name of an option, expressed as a QName: the
            namespace URI of the QName <rfc2119>should</rfc2119> be a URI controlled by the vendor
            of the XSLT processor. The meaning of the associated value is <termref
                     def="implementation-defined"
                     >implementation-defined</termref>. Implementations
                <rfc2119>should</rfc2119> ignore options whose names are in an unrecognized
            namespace. Default is the empty map.</fos:meaning>
               <fos:type>{ xs:QName, item()* }</fos:type>
               <fos:default>Empty map</fos:default>
            </fos:option>

            <fos:option key="xslt-version">
               <fos:applies-to>1.0, 2.0, 3.0, 4.0</fos:applies-to>
               <fos:meaning>The minimum level of the XSLT language that the processor must support.</fos:meaning>
               <fos:type>xs:decimal</fos:type>
               <fos:default-description>The <code>[xsl:]version</code> attribute at the outermost level of the
            stylesheet.</fos:default-description>
            </fos:option>

         </fos:options>




         <p>The result of the transformation is returned as a map. There is one entry in the map for the principal result document, and one
            for each secondary result document. The key is a URI in the form of an <code>xs:string</code> value. The key for the principal
            result document is the base output URI if specified, or the string <code>"output"</code> otherwise. The key for secondary
            result documents is the URI of the document, as an absolute URI. The associated value in each entry depends on the requested
            delivery format. If the delivery format is <code>document</code>, the value is a document node. If the delivery format is
            <code>serialized</code>, the value is a string containing the serialized result. </p>

         <p>Where nodes are passed to or from the transformation, for example as the value of a stylesheet parameter or the result of a function, 
            they <rfc2119>should</rfc2119> if possible retain their node identity, their base URI, their type annotations, and their relationships to all other nodes 
            in the containing tree (including ancestors and siblings). If this is not possible, for example because the only way of passing nodes 
            to the chosen XSLT implementation is by serializing and re-parsing, then a node <rfc2119>may</rfc2119> be passed in the form of a deep 
            copy, which may lose information about the identity of the node, about its ancestors and siblings, about its base URI, about its type annotation, and about its 
            relationships to other nodes passed across the interface.</p>

         <p>It is <termref def="implementation-defined"
               >implementation-defined</termref> whether the XSLT transformation is executed
            within the same <termref
               def="execution-scope">execution scope</termref> as the calling code.</p>

         <p>The function is <termref def="dt-nondeterministic"
               >nondeterministic</termref> in that it is 
            <termref
               def="implementation-dependent"
               >implementation-dependent</termref> whether running the function twice against the same
         inputs produces identical results. The results of two invocations may differ in the identity of any returned nodes; they may also
         differ in other respects, for example because the value of <function>fn:current-dateTime</function> is different for the two invocations,
         or because the contents of external documents accessed using <function>fn:doc</function> or <code>xsl:source-document</code> change between
         one invocation and the next.</p>




      </fos:rules>
      <fos:errors>
         <p>A dynamic error is raised <errorref class="XT" code="0001" type="dynamic"
            /> if the transformation cannot be invoked 
            because no suitable XSLT processor is available. This includes (but is not limited to) the following cases:</p>
         <olist>
            <item>
               <p>No XSLT processor is available;</p>
            </item>
            <item>
               <p>No XSLT processor supporting the requested version of XSLT is available;</p>
            </item>
            <item>
               <p>The XSLT processor API does not support some requested feature (for example, the ability to supply tunnel parameters externally);</p>
            </item>
         </olist>
         <p>A dynamic error is raised <errorref class="XT" code="0002" type="dynamic"
            /> if an error is detected in the supplied
            parameters (for example if two mutually exclusive parameters are supplied).</p>
         <p>If a static or dynamic error is reported by the XSLT processor, this function fails with a dynamic error, retaining the XSLT error code.</p>
         <p>A dynamic error is raised <errorref class="XT" code="0003" type="dynamic"
               /> if the XSLT transformation invoked by a call on
            <function>fn:transform</function> fails with a static or dynamic error, and no more specific error code is available. </p>
         <note>
            <p>XSLT 1.0 does not define any error codes, so this is the likely outcome with an XSLT 1.0 processor. XSLT 2.0 and 3.0 do
         define error codes, but some APIs do not expose them. If multiple errors are signaled by the transformation (which is most likely
         to happen with static errors) then the error code should where possible be that of one of these errors, chosen arbitrarily; the processor
         may make details of additional errors available to the application in an <termref
                  def="implementation-defined">implementation-defined</termref>
         way.</p>
         </note>
         <p>A dynamic error is raised <errorref class="XT" code="0004" type="dynamic"
            /> if the use of this function (or of selected options)
            has been externally disabled, for example for security reasons.</p>
         <p>A dynamic error is raised <errorref class="XT" code="0006" type="dynamic"
            /> if the transformation produces output containing
            characters available only in XML 1.1, and the calling processor cannot handle such characters.</p>
         <p>Recursive use of the <function>fn:transform</function> function may lead to catastrophic failures such as
         non-termination or stack overflow. No error code is assigned to such conditions, since they cannot necessarily
         be detected by the processor.</p>

      </fos:errors>
      <fos:notes>

         <p>As with all other functions in this specification, conformance requirements depend on the host language.
            For example, a host language might specify that provision of this function is optional, or that it is excluded entirely,
            or that implementations are required to support a particular set of values for the <code>xslt-version</code>
            parameter.</p>

         <p>Even where support for this function is mandatory, it is <rfc2119>recommended</rfc2119> for security reasons that implementations
            should provide a user option to disable its use, or to disable aspects of its functionality such as
            the ability to write to persistent resources.</p>


      </fos:notes>
      <fos:examples>
         <fos:example>
            <p>The following example loads a stylesheet from the location <code>render.xsl</code>,
               applies it to a document loaded from <code>test.xml</code>, and uses an XPath expression
               to examine the result:</p>
            <eg><![CDATA[
let $result := transform({
  "stylesheet-location": "render.xsl",
  "source-node": doc('test.xml')
})
return $result?output//body  
               ]]></eg>
         </fos:example>
      </fos:examples>

   </fos:function>


   <fos:function name="random-number-generator" prefix="fn">
      <fos:signatures>
         <fos:proto name="random-number-generator" return-type-ref="random-number-generator-record">
            <fos:arg name="seed" type="xs:anyAtomicType?" default="()"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
         
      </fos:properties>
      <fos:summary>
         <p>Returns a random number generator, which can be used to generate sequences of random numbers.</p>
      </fos:summary>
      <fos:rules>
         <p diff="chg" at="2022-12-19"
               >The function returns a random number generator. A random number generator is represented as a value of type 
            <code>random-number-generator-record</code>, defined in
         <specref ref="random-number-generator-record"/>.</p>
        
         <p>Calling the <function>fn:random-number-generator</function> function with
            the empty sequence as <code>$seed</code> is equivalent to calling the single-argument
            form of the function with an implementation-dependent seed.</p>
         <p>If a <code>$seed</code> is supplied, it may be an atomic item of any type.</p>
         <p>Both forms of the function are <termref def="dt-deterministic"
               />: calling the function twice with the same arguments, within a single
         <termref
               def="execution-scope">execution scope</termref>, produces the same results.</p>


         <p>The value of the <code>number</code> entry <rfc2119>should</rfc2119> be such that <phrase diff="del" at="B">all eligible <code>xs:double</code>
            values are equally likely to be chosen</phrase> <phrase diff="add" at="B">the distribution of numbers is uniform: for example, the probability of the
         number being in the range 0.1e0 to 0.2e0 is the same as the probability of its being in the range 0.8e0 to 0.9e0</phrase>.</p>

         <p>The function returned in the <code>permute</code> entry <rfc2119>should</rfc2119> be such that all permutations 
            of the supplied sequence are equally likely to be chosen.</p>

         <p>The map returned by the <function>fn:random-number-generator</function> function <rfc2119>may</rfc2119> contain additional entries beyond
            those specified here, but it <rfc2119>must</rfc2119> match the  
            <phrase
               diff="chg" at="A"
               >record type defined above</phrase>. The meaning of any additional entries
         is <termref
               def="implementation-defined"
               >implementation-defined</termref>. To avoid conflict with any future version of this specification, the keys of any
         such entries <rfc2119>should</rfc2119> start with an underscore character.</p>
      </fos:rules>
      <fos:notes>
         <p>It is not meaningful to ask whether the functions returned in the <code>next</code> and <code>permute</code>
            functions resulting from two separate calls with the same seed are “the same function”, but the functions must be equivalent in the sense
            that calling them produces the same sequence of random numbers.</p>
         <p>The repeatability of the results of function calls in different execution scopes is outside the scope of this
            specification. It is <rfc2119>recommended</rfc2119> that when the same seed is provided explicitly, the same random number sequence
            should be delivered even in different execution scopes; while if no seed is provided, the processor should choose a seed
            that is likely to be different from one execution scope to another. (The same effect can be achieved explicitly by using
         <code>fn:current-dateTime()</code> as a seed.)</p>
         <p>The specification does not place strong conformance requirements on the actual randomness of the result; this is left to 
            the implementation. It is desirable, for example, when generating a sequence
         of random numbers that the sequence should not get into a repeating loop; but the specification does not attempt to dictate this.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>random-number-generator()?permute(1 to 100)</fos:expression>
               <fos:result narrative="true">A random permutation of the integers in the range
               <code>1</code> to <code>100</code></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>random-number-generator()?permute($seq)[1 to (count($seq) idiv 10)]</fos:expression>
               <fos:result narrative="true">A 10% sample of the items in an input sequence <code>$seq</code>, chosen at random</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPST0008"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
         <fos:example>

            <p>The following XQuery code produces a random sequence of 200 <code>xs:double</code>
            values in the range zero to one:</p>
            <eg>
declare %public function local:random-sequence($length as xs:integer) as xs:double* {
  local:random-sequence($length, random-number-generator())
};
declare %private function local:random-sequence(
  $length as xs:integer, 
  $record as record(number as xs:double, next as fn(*))
) as xs:double* {
  if ($length != 0) {
    $record?number,
    local:random-sequence($length - 1, $record?next())
  }
};
local:random-sequence(200)
            </eg>
            <p>An equivalent result can be achieved with <function>fn:fold-left</function>:</p>
            <eg>
tail(fold-left(
  (1 to 200),
  random-number-generator(),
  fn($result) { head($result) ! (?next(), ?number), tail($result) }
))
            </eg>

         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change>
            <p>The 3.1 specification suggested that every value in the result range should have the same chance 
            of being chosen. This has been corrected to say that the distribution should be arithmetically uniform
            (because there are as many <code>xs:double</code> values between 0.01 and 0.1 as there are between 
            0.1 and 1.0).</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="every" prefix="fn">
      <fos:signatures>
         <fos:proto name="every" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="predicate" type="(fn(item(), xs:integer) as xs:boolean?)?"
               default="fn:boolean#1" example="fn:boolean#1" usage="inspection" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if every item in the input sequence matches a supplied predicate.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns true if <code>$input</code> is empty, or if <code>$predicate($item, $pos)</code>
            returns true for every item <code>$item</code> at position <code>$pos</code> (1-based) in <code>$input</code>.</p>
      
      </fos:rules>
      
      
      <fos:equivalent style="xpath-expression">
count(filter($input, $predicate)) = count($input)
      </fos:equivalent>
      <fos:errors>
         <p>An error is raised if the <code>$predicate</code> function raises an error. In particular,
         when the default predicate <code>fn:boolean#1</code> is used, an error is raised if an
         item has no effective boolean value.</p>
      </fos:errors>
      <fos:notes>
         <p>It is possible for the supplied <code>$predicate</code> to be a function whose arity is less than two.
            The coercion rules mean that the additional parameters are effectively ignored. Frequently a predicate
            function will only consider the item itself, and disregard its position in the sequence.</p>
         <p>The predicate is required to return either <code>true</code>, <code>false</code>, or the empty
            sequence (which is treated as <code>false</code>). A predicate such as <code>fn { self::h1 }</code>
            results in a type error because it returns a node, not a boolean.</p>
         <p>The implementation <rfc2119>may</rfc2119> deliver a result as soon as one item is found for which the predicate
         returns <code>false</code>; it is not required to evaluate the predicate for every item,
         nor is it required to examine items sequentially from left to right.</p>
      
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>every(())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>every((1 = 1, 2 = 2, 3 = 4))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>every((), boolean#1)</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>every((1, 3, 7), fn { . mod 2 = 1 })</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>every(-5 to +5, fn { . ge 0 })</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>every(
  ("January", "February", "March", "April",
   "September", "October", "November", "December"),
  contains(?, "r")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>every(
  ("January", "February", "March", "April",
   "September", "October", "November", "December")
  =!> contains("r")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>every((1, 2, number('NaN')))</fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>The effective boolean value of NaN is false.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>every(1 to 5, fn($num, $pos) { $num = $pos })</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test spec="XQuery">
               <fos:expression><eg><![CDATA[
let $dl := <dl><dt>Morgawr</dt><dd>Sea giant</dd></dl>
return every($dl/*, fn($elem, $pos) {
  name($elem) = (
    if (($pos mod 2)) then "dt" else "dd"
  )
})]]></eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-13"><p>New in 4.0</p></fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="char" prefix="fn">
      <fos:signatures>
         <fos:proto name="char" return-type="xs:string">
            <fos:arg name="value" type="(xs:string | xs:positiveInteger)"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns a string containing a particular character or glyph.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a string, generally containing a single <termref
               def="character">character</termref> or glyph, identified by <code>$value</code>.</p>
         <p>The supplied value of <code>$value</code> must be one of the following:</p>
         <olist>
            <item><p>A Unicode codepoint, supplied as an integer. For example <code>fn:char(9)</code>
            returns the tab character.</p></item>
            <item><p>An HTML5 character reference name (often referred to as an entity name) as defined
               at <loc href="https://html.spec.whatwg.org/multipage/named-characters.html">https://html.spec.whatwg.org/multipage/named-characters.html</loc>. The name is
               written with no leading ampersand and no trailing semicolon.
               For example <code>fn:char("pi")</code> represents the character
               <char>U+03C0</char> and <code>fn:char("nbsp")</code> returns 
               <char>U+00A0</char>.</p>
               <p>A processor <rfc2119>may</rfc2119> recognize additional character reference names defined in
                  other versions of HTML. Character reference names are case-sensitive.</p>
               <p>In the event that the HTML5 character reference name identifies a string
               comprising multiple codepoints, that string is returned.</p>
               <p>[TODO: add a proper bibliographic reference.]</p></item>
            <item><p>A backslash-escape sequence from the set <code>\n</code> (<char>U+000A</char>), 
               <code>\r</code> (<char>U+000D</char>),
               or <code>\t</code> (<char>U+0009</char>).</p></item>
            
            
         </olist>
         <p diff="chg" at="2023-06-12">The result must consist of
         <termref def="dt-permitted-character">permitted characters</termref>.
         For example <code>fn:char(0xDEAD)</code> is invalid because it is in the surrogate range.</p>
      </fos:rules>
      <fos:errors>
         <p>The function fails with a dynamic error <errorref
               class="CH" code="0005"/> if <code>$value</code> is not a valid
            representation of a <termref def="dt-permitted-character"/> 
            or sequence of permitted characters.
         </p>
      </fos:errors>
      <fos:notes>
         <p>Although all Unicode characters can appear in string literals (the delimiting quotation marks can be
         escaped by doubling them), some characters are not visually distinctive, so representing them by name
         may make code more readable. In addition, there may be contexts where it is necessary or prudent to
         write XPath expressions using ASCII characters only, for example where an expression is used in the query
         part of a URI.</p>
         <p>A few HTML5 character reference names identify glyphs whose Unicode
         representation uses multiple codepoints. For example, the name
            <code>NotEqualTilde</code> refers to the glyph <code>≂̸</code> which is expressed
            using the two codepoints <char>U+2242</char>, <char>U+0338</char>. In such cases the string length of
         the result of the function will exceed one.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>char("aacute")</fos:expression>
               <fos:result>"&#xE1;"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>char("eth")</fos:expression>
               <fos:result>"&#xF0;"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>char(9)</fos:expression>
               <fos:result>codepoints-to-string(9)</fos:result>
               <fos:postamble>The character <emph>tab</emph></fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>char("\t")</fos:expression>
               <fos:result>codepoints-to-string(9)</fos:result>
               <fos:postamble>The character <emph>tab</emph></fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>char(0x20)</fos:expression>
               <fos:result>" "</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>char(0x1D1CA)</fos:expression>
               <fos:result>"&#x1D1CA;"</fos:result>
               <fos:postamble>The character MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>char("NotEqualTilde")</fos:expression>
               <fos:result>codepoints-to-string((8770, 824))</fos:result>
               <fos:postamble>This HTML5 character reference name expands to multiple codepoints.</fos:postamble>
            </fos:test>
 
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="121 989" PR="261 306 993" date="2023-01-10"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="characters" prefix="fn">
      <fos:signatures>
         <fos:proto name="characters" return-type="xs:string*">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Splits the supplied string into a sequence of single-character strings.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence of strings, each string having length 1, containing
            the corresponding <termref
               def="character">character</termref> in <code>$value</code>.</p>
         <p>If <code>$value</code> is a zero-length string or the empty sequence, the function returns
            the empty sequence.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
         string-to-codepoints($value) ! codepoints-to-string(.)
      </fos:equivalent>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>characters("Thérèse")</fos:expression>
               <fos:result>"T", "h", "é", "r", "è", "s", "e"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>characters("")</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>characters(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>characters("Banana") => index-of("a")</fos:expression>
               <fos:result>2, 4, 6</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>characters("stretch") => string-join("-")</fos:expression>
               <fos:result>"s-t-r-e-t-c-h"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>"Banana"
=> characters()
=> reverse()
=> string-join()</eg></fos:expression>
               <fos:result>"ananaB"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="graphemes" prefix="fn">
      <fos:signatures>
         <fos:proto name="graphemes" return-type="xs:string*">
            <fos:arg name="value" type="xs:string?"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties arity="1">
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Splits the supplied string into a sequence of single-grapheme strings.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence of strings. Each string in the sequence contains one or
            more <termref def="character">character</termref>s that collectively constitute a single
            extended grapheme cluster, as defined by <bibref ref="UNICODE-TR29"/>.</p>
         <p>If <code>$value</code> is a zero-length string or the empty sequence, the function returns
            the empty sequence.</p>
         
      </fos:rules>
      <fos:notes>
         <p>The resultant sequence of strings are extended graphemes, not legacy graphemes (see 
            <bibref ref="UNICODE-TR29"/>).</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>graphemes("a" || char(0x308) || "b")</fos:expression>
               <fos:result>"a" || char(0x308), "b"</fos:result>
               <fos:postamble>a + ◌̈ + b, three characters, two graphemes</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>graphemes("")</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>graphemes(())</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>graphemes(char('\r') || char('\n'))</fos:expression>
               <fos:result>char('\r') || char('\n')</fos:result>
               <fos:postamble>Carriage return + line feed, two characters, one
                  grapheme</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>graphemes(char(0x1F476) || char(0x200D) || char(0x1F6D1))</fos:expression>
               <fos:result>char(0x1F476) || char(0x200D) || char(0x1F6D1)</fos:result>
               <fos:postamble>👶 +ZWJ + 🛑, three characters, one grapheme</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>graphemes("कत")</fos:expression>
               <fos:result>"क", "त"</fos:result>
               <fos:postamble>क + त, two characters, two graphemes</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>graphemes("क" || char(0x93C) || char(0x200D) || char(0x94D) || "त")</fos:expression>
               <fos:result>"क" || char(0x93C) || char(0x200D) || char(0x94D) || "त"</fos:result>
               <fos:postamble>क + ◌़ + ZWJ + ◌् + त, five characters, one grapheme</fos:postamble>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="73" PR="1068" date="2024-05-15"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>



   <fos:function name="highest" prefix="fn">
      <fos:signatures>
         <fos:proto name="highest" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="collation" type="xs:string?" usage="absorption" default="fn:default-collation()" note="default-on-empty"/>
            <fos:arg name="key" type="(fn(item()) as xs:anyAtomicType*)?" usage="inspection" default="fn:data#1" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>


      <fos:summary>
         <p>Returns a value that is greater than or equal to every other value appearing in the input sequence.</p>
      </fos:summary>
      <fos:rules>
         <p>The second argument, <code>$collation</code>, defaults to <code>()</code>.</p>
         <p>Supplying an empty
            sequence as <code>$collation</code> is equivalent to supplying 
            <code>fn:default-collation()</code>. For more
            information on collations see <specref
               ref="choosing-a-collation"/>.</p>
         
         <p>The third argument, <code>$key</code>, defaults to the function <code>data#1</code>.</p>
         
         <p>Let <code>$modified-key</code> be the function:</p>
         <eg>fn($item) {
  $key($item) => data() ! (
    if (. instance of xs:untypedAtomic) then xs:double(.) else .
  )
}</eg>
         
         <p>That is, the supplied function for computing key values is wrapped in a function that
            converts any <code>xs:untypedAtomic</code> values in its result to <code>xs:double</code>. This makes
            the function consistent with the behavior of <function>fn:min</function> and <function>fn:max</function>,
            but inconsistent with <function>fn:sort</function>, which treats untyped values as strings.</p>
         
         <p>The result of the function is obtained as follows:</p>
         <ulist>
            <item>
               <p>If the input is an empty sequence, the result is an empty sequence.</p>
            </item>
            <item>
               <p>The input sequence is sorted, by applying the function 
                  <code>fn:sort($input, $collation, $modified-key)</code>.</p>
            </item>
            <item>
               <p>Let <var>$C</var> be the selected collation, or the default collation where applicable.</p>
            </item>
            <item>
               <p>Let <var>$B</var> be the last item in the sorted sequence.</p>
            </item>
            <item>
               <p>The function returns those items <var>$A</var> from the input sequence 
                  that are <termref def="dt-contextually-equal"/> to <code>$B</code>, 
                  retaining their order.
               </p>
            </item>
            
         </ulist>
         
         
      </fos:rules>
      <fos:errors>
         <p>If the set of computed keys contains <code>xs:untypedAtomic</code> values that are not 
            castable to <code>xs:double</code> then the
            operation will fail with a dynamic error (<xerrorref
               spec="FO" class="RG" code="0001"/>).
         </p>
         <p>If the set of computed keys contains values that are not comparable using 
            the <code>lt</code> operator then the sort 
            operation will fail with a type error (<xerrorref
               spec="XP" class="TY" code="0004"/>).
         </p>
      </fos:errors>
      <fos:examples>
         <fos:variable name="e" id="v-highest-e"><![CDATA[<a x="10" y="5" z="2"/>]]></fos:variable>
         <fos:example>
            <fos:test use="v-highest-e" spec="XQuery">
               <fos:expression>highest($e/@*) ! name()</fos:expression>
               <fos:result>"x"</fos:result>
               <fos:postamble>By default, untyped values are compared as numbers.</fos:postamble>
            </fos:test>
            <fos:test use="v-highest-e" spec="XQuery">
               <fos:expression>highest($e/@*, (), string#1) ! name()</fos:expression>
               <fos:result>"y"</fos:result>
               <fos:postamble>Here, the attribute values are compared as strings.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>highest(("red", "green", "blue"), (), string-length#1)</fos:expression>
               <fos:result>"green"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>highest(
  ("red", "green", "blue"),
  key := {
    "red"  : xs:hexBinary('FF0000'),
    "green": xs:hexBinary('008000'),
    "blue" : xs:hexBinary('0000FF')
  }
)</eg></fos:expression>
               <fos:result>"red"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>highest(
  ("red", "orange", "yellow", "green", "blue", "indigo", "violet"),
  key := string-length#1
)</eg></fos:expression>
               <fos:result>"orange", "yellow", "indigo", "violet"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>highest(1 to 25, (), fn { . idiv 10 })</fos:expression>
               <fos:result>20, 21, 22, 23, 24, 25</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>highest(//employee, (), fn { xs:decimal(salary) })</fos:expression>
               <fos:result narrative="true">The employees having the highest salary.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="index-where" prefix="fn">
      <fos:signatures>
         <fos:proto name="index-where" return-type="xs:integer*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="predicate" type="fn(item(), xs:integer) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the positions in an input sequence of items that match a supplied predicate.</p>
      </fos:summary>
      <fos:rules>

         <p>The result of the function is a sequence of integers, in monotonic ascending order, representing
            the 1-based positions in the input sequence of those items for which the supplied predicate function
            returns <code>true</code>. A return value of <code>()</code> from the predicate function
         is treated as <code>false</code>.</p>

      </fos:rules>
      <fos:equivalent style="xpath-expression">
for-each(
  $input,
  fn($item, $pos) { if ($predicate($item, $pos)) { $pos } }
)
      </fos:equivalent>

      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>index-where((), boolean#1)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>index-where((0, 4, 9), boolean#1)</fos:expression>
               <fos:result>2, 3</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>index-where(1 to 10, fn { . mod 2 = 0 })</fos:expression>
               <fos:result>2, 4, 6, 8, 10</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>index-where(
  ("January", "February", "March", "April", "May", "June",
   "July", "August", "September", "October", "November", "December"),
  contains(?, "r")
)</eg></fos:expression>
               <fos:result>1, 2, 3, 4, 9, 10, 11, 12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[index-where(
  ( 1, 8, 2, 7, 3 ),
  fn($item, $pos) { $item < 5 and $pos > 2 }
)]]></eg></fos:expression>
               <fos:result>3, 5</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0</p></fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="is-NaN" prefix="fn">
      <fos:signatures>
         <fos:proto name="is-NaN" return-type="xs:boolean">
            <fos:arg name="value" type="xs:anyAtomicType"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if the argument is the <code>xs:float</code> or <code>xs:double</code> value <code>NaN</code>.</p>
      </fos:summary>
      <fos:rules>

         <p>The function returns <code>true</code> if <code>$value</code> is the <code>xs:float</code> or <code>xs:double</code> value <code>NaN</code>;
            otherwise it returns <code>false</code>.</p>

      </fos:rules>


      <fos:examples>

         <fos:example>
            <fos:test>
               <fos:expression>is-NaN(23)</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>is-NaN("NaN")</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>is-NaN(number("twenty-three"))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>is-NaN(math:sqrt(-1))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>

      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

 

   <fos:function name="take-while" prefix="fn">
      <fos:signatures>
         <fos:proto name="take-while" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="predicate" type="fn(item(), xs:integer) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns items from the input sequence prior to the first one that fails to match a supplied predicate.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns all items in the sequence prior to the first one where the result of
         calling the supplied <code>$predicate</code> function, with the current item and its position
         as arguments, returns the value <code>false</code> or <code>()</code>.</p>
         <p>If every item in the sequence satisfies the predicate, then <code>$input</code> is returned
         in its entirety.</p>
         
      </fos:rules>
      <fos:equivalent style="xquery-expression">
for $item at $pos in $input
while $predicate($item, $pos)
return $item        
      </fos:equivalent>
      
      <fos:notes>
         <p>There is no analogous <code>drop-while</code> or <code>skip-while</code> function,
         as found in some functional programming languages. The effect of 
            <code>drop-while($input, $predicate)</code> can be achieved by calling
         <code>fn:subsequence-where($input, fn { not($predicate(.)) })</code>.</p>
      </fos:notes>
      

      <fos:examples>

         <fos:example>
            <fos:test>
               <fos:expression>take-while(10 to 20, fn { . le 12 })</fos:expression>
               <fos:result>10, 11, 12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>take-while(10 to 20, fn { . lt 100 })</fos:expression>
               <fos:result>10 to 20</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>take-while((), boolean#1)</fos:expression>
               <fos:result>()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>take-while(
  ("A", "B", "C", " ", "E"), 
  fn { boolean(normalize-space()) }
 )</eg></fos:expression>
               <fos:result>"A", "B", "C"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[parse-xml("<doc><p/><p/><h2/><img/><p/></doc>")/doc/*
=> take-while(fn { boolean(self::p) })
=> count()]]></eg></fos:expression>
               <fos:result>2</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg><![CDATA[
("Aardvark", "Antelope", "Bison", "Buffalo", "Camel", "Dingo")
=> take-while(starts-with(?, "A"))]]></eg></fos:expression>
               <fos:result>"Aardvark", "Antelope"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>take-while(10 to 20, fn($num, $pos) { $num lt 18 and $pos lt 4 })</eg></fos:expression>
               <fos:result>10, 11, 12</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>take-while(
  characters("ABCD-123"), 
  fn($ch, $pos) { $pos lt 4 and $ch ne '-' }
) => string-join()
</eg></fos:expression>
               <fos:result>"ABC"</fos:result>
            </fos:test>  
            <fos:test>
               <fos:expression><eg>take-while(
  ("A", "a", "B", "b", "C", "D", "d"),
   fn($ch, $pos) {
     matches($ch, if ($pos mod 2 eq 1) then "\p{Lu}" else "\p{Ll}")
   }
 )
</eg></fos:expression>
               <fos:result>"A", "a", "B", "b", "C"</fos:result>
            </fos:test>     
         </fos:example>

      </fos:examples>
      <fos:changes>
         <fos:change issue="1002 1038" PR="1046" date="2004-03-05">
            <p>New in 4.0</p>
         </fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>
  


   <fos:function name="lowest" prefix="fn">
      <fos:signatures>
         <fos:proto name="lowest" return-type="item()*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="collation" type="xs:string?" usage="absorption" default="fn:default-collation()" note="default-on-empty"/>
            <fos:arg name="key" type="(fn(item()) as xs:anyAtomicType*)?" usage="inspection" default="fn:data#1" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>


      <fos:summary>
         <p>Returns those items from a supplied sequence that have the lowest value of a sort key, where
            the sort key can be computed using a caller-supplied function.</p>
      </fos:summary>
      <fos:rules>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>
         <p>Let <code>$modified-key</code> be the function:</p>
         <eg>fn($item) {
  $key($item) => data() ! (
    if (. instance of xs:untypedAtomic) then xs:double(.) else .
  )
}</eg>
         
         <p>That is, the supplied function for computing key values is wrapped in a function that
            converts any <code>xs:untypedAtomic</code> values in its result to <code>xs:double</code>. This makes
            the function consistent with the behavior of <function>fn:min</function> and <function>fn:max</function>,
            but inconsistent with <function>fn:sort</function>, which treats untyped values as strings.</p>
         
         <p>The result of the function is obtained as follows:</p>
         <ulist>
            <item>
               <p>If the input is the empty sequence, the result is the empty sequence.</p>
            </item>
            <item>
               <p>The input sequence is sorted, by applying the function 
                  <code>fn:sort($input, $collation, $modified-key)</code>.</p>
            </item>
            <item>
               <p>Let <var>$C</var> be the selected collation, or the default collation where applicable.</p>
            </item>
            <item>
               <p>Let <var>$B</var> be the first item in the sorted sequence.</p>
            </item>
            <item>
               <p>The function returns those items <var>$A</var> from the input sequence 
                  that are <termref def="dt-contextually-equal"/> to <code>$B</code>, 
                  retaining their order.
               </p>
            </item>
            
         </ulist>
      </fos:rules>
      <fos:errors>
         <p>If the set of computed keys contains <code>xs:untypedAtomic</code> values that are not 
            castable to <code>xs:double</code> then the
            operation will fail with a dynamic error (<xerrorref
               spec="FO" class="RG" code="0001"/>).
         </p>
         <p>If the set of computed keys contains values that are not comparable using 
            the <code>lt</code> operator then the sort 
            operation will fail with a type error (<xerrorref
               spec="XP" class="TY" code="0004"/>).
         </p>
      </fos:errors>


      <fos:examples>
         <fos:variable name="e" id="v-lowest-e"><![CDATA[<a x="10" y="5" z="2"/>]]></fos:variable>
         <fos:example>
            <fos:test use="v-lowest-e" spec="XQuery">
               <fos:expression>lowest($e/@*) ! name()</fos:expression>
               <fos:result>"z"</fos:result>
               <fos:postamble>By default, untyped values are compared as numbers.</fos:postamble>
            </fos:test>
            <fos:test use="v-lowest-e" spec="XQuery">
               <fos:expression>lowest($e/@*, (), string#1) ! name()</fos:expression>
               <fos:result>"x"</fos:result>
               <fos:postamble>Here, the attribute values are compared as strings.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>lowest(("red", "green", "blue"), (), string-length#1)</fos:expression>
               <fos:result>"red"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>lowest(
  ("red", "green", "blue"),
  key := {
    "red"  : xs:hexBinary('FF0000'),
    "green": xs:hexBinary('008000'),
    "blue" : xs:hexBinary('0000FF')
  }
)</eg></fos:expression>
               <fos:result>"blue"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>lowest(
  ("April", "June", "July", "August"),
  key := string-length#1
)</eg></fos:expression>
               <fos:result>"June", "July"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>lowest(1 to 25, (), fn { . idiv 10 })</fos:expression>
               <fos:result>1, 2, 3, 4, 5, 6, 7, 8, 9</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>lowest(//employee, (), fn { xs:decimal(salary) })</fos:expression>
               <fos:result narrative="true">The employees having the lowest salary.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="some" prefix="fn">
      <fos:signatures>
         <fos:proto name="some" return-type="xs:boolean">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="predicate" type="(fn(item(), xs:integer) as xs:boolean?)?"
               default="fn:boolean#1" example="fn:boolean#1" usage="inspection" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns <code>true</code> if at least one item in the input sequence matches a supplied predicate.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns true if (and only if) there is an item <code>$item</code> at position <code>$pos</code>
            in the input sequence such that <code>$predicate($item, $pos)</code> returns true.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
exists(filter($input, $predicate))         
      </fos:equivalent>
      <fos:errors>
         <p>An error is raised if the <code>$predicate</code> function raises an error. In particular,
         when the default predicate <code>fn:boolean#1</code> is used, an error is raised if an
         item has no effective boolean value.</p>
      </fos:errors>
      <fos:notes>
         <p>It is possible for the supplied <code>$predicate</code> to be a function whose arity is less than two.
            The coercion rules mean that the additional parameters are effectively ignored. Frequently a predicate
            function will only consider the item itself, and disregard its position in the sequence.</p>
         <p>The predicate is required to return either <code>true</code>, <code>false</code>, or the empty
            sequence (which is treated as <code>false</code>). A predicate such as <code>fn { self::h1 }</code>
            results in a type error because it returns a node, not a boolean.</p>
         <p>The implementation <rfc2119>may</rfc2119> deliver a result as soon as one item is found for which the predicate
         returns <code>true</code>; it is not required to evaluate the predicate for every item,
         nor is it required to examine items sequentially from left to right.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>some(())</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>some((1 = 1, 2 = 2, 3 = 4))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>some((), boolean#1)</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>some((1, 3, 7), fn { . mod 2 = 1 })</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>some(-5 to +5, fn { . ge 0 })</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>some(
  ("January", "February", "March", "April",
   "September", "October", "November", "December"),
  contains(?, "z")
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>some(
  ("January", "February", "March", "April",
   "September", "October", "November", "December")
  =!> contains("r")
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression>some(("", 0, number('NaN')))</fos:expression>
               <fos:result>false()</fos:result>
               <fos:postamble>The effective boolean value in each case is false.</fos:postamble>
            </fos:test>
            <fos:test>
               <fos:expression>some(reverse(1 to 5), fn($num, $pos) { $num = $pos })</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-13">
            <p>New in 4.0</p>
         </fos:change>
         <fos:change issue="1171" PR="1182" date="2024-05-07">
            <p>The <code>$predicate</code> callback function may return the empty sequence (meaning <code>false</code>).</p>
         </fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="all-equal" prefix="fn">
      <fos:signatures>
         <fos:proto name="all-equal" return-type="xs:boolean">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="collation" type="xs:string?" usage="absorption" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>


      <fos:summary>
         <p>Returns <code>true</code> if all items in a supplied sequence (after atomization) are 
            <termref def="dt-contextually-equal"/>.</p>
      </fos:summary>

      <fos:rules>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>


         <p>The result of the function <code>fn:all-equal($values, $collation)</code> is <code>true</code> if and only if the result
            of <code>fn:count(fn:distinct-values($values, $collation)) le 1</code> is <code>true</code> (that is, if the sequence
            is empty, or if all the items in the sequence are equal under the rules of the 
            <function>fn:distinct-values</function> function).</p>
      </fos:rules>
      

      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>all-equal((1, 2, 3))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>all-equal((1, 1.0, 1.0e0))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>all-equal("one")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>all-equal(())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>        
         <fos:example>
            <fos:test>
               <fos:expression>all-equal((xs:float('NaN'), xs:double('NaN')))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>all-equal(
  ("ABC", "abc"),
  "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
)</eg></fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>all-equal(//p/@class)</fos:expression>
               <fos:result narrative="true">Returns <code>true</code> if all
                <code>p</code> elements have the same value for <code>@class</code>.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
            <fos:test>
               <fos:expression>all-equal(* ! node-name())</fos:expression>
               <fos:result narrative="true">Returns <code>true</code> if all
               element children of the context node have the same name.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0. Originally proposed under the name <code role="example">fn:uniform</code></p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="all-different" prefix="fn">
      <fos:signatures>
         <fos:proto name="all-different" return-type="xs:boolean">
            <fos:arg name="values" type="xs:anyAtomicType*"/>
            <fos:arg name="collation" type="xs:string?" usage="absorption" default="fn:default-collation()" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property dependency="collations">context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>


      <fos:summary>
         <p>Returns <code>true</code> if no two items in a supplied sequence are 
            <termref def="dt-contextually-equal"/>.</p>
      </fos:summary>

      <fos:rules>
         <p>The collation used by this function is determined according to the rules in <specref
               ref="choosing-a-collation"/>.</p>


         <p>The result of the function <code>fn:all-different($values, $collation)</code> is <code>true</code> if and only if the result
            of <code>fn:count(fn:distinct-values($values, $collation)) eq fn:count($values)</code> is <code>true</code> 
            (that is, if the sequence
            is empty, or if all the items in the sequence are 
            <termref def="dt-contextually-equal">contextually unequal</termref> under the rules used by the 
            <function>fn:distinct-values</function> function).</p>
      </fos:rules>
      

      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>all-different((1, 2, 3))</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>all-different((1, 1.0, 1.0e0))</fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>all-different("one")</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>all-different(())</fos:expression>
               <fos:result>true()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>all-different(
  ("ABC", "abc"),
  "http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive"
)</eg></fos:expression>
               <fos:result>false()</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>fn:all-different(//employee/@ssn)</fos:expression>
               <fos:result narrative="true">Returns <code>true</code> if no two employees have the same value for their
            <code>@ssn</code> attribute.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test> 
               <fos:expression>fn:all-different(* ! fn:node-name())</fos:expression>
               <fos:result narrative="true">Returns <code>true</code> if all
                  element children of the context node have distinct names.</fos:result>
               <fos:test-assertion>
                  <result xmlns="http://www.w3.org/2010/09/qt-fots-catalog">
                     <error code="XPDY0002"/>
                  </result>
               </fos:test-assertion>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change date="2022-09-20"><p>New in 4.0. Originally proposed under the name <code role="example">fn:unique</code></p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="parse-uri" prefix="fn" diff="add">
      <fos:signatures>
         <fos:proto name="parse-uri" return-type-ref="uri-structure-record" return-type-ref-occurs="?">
            <fos:arg name="value" type="xs:string?"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>

      <fos:summary>
         <p>Parses the URI provided and returns a map of its parts.</p>
      </fos:summary>

      <fos:rules>
         <p>If <code>$value</code> is the empty sequence, the result is the empty sequence.</p>

         <p>The function parses the <code>$value</code> provided,
         returning a map containing its constituent parts: scheme,
         authority components, path, etc.
         In addition to parsing URIs as defined by <bibref ref="rfc3986"/>
         (and <bibref ref="rfc3987"/>), this function also attempts to
         account for strings that are not valid URIs but that often appear
         in URI-adjacent spaces, such as file names. Not all such strings
         can be successfully parsed as URIs.</p>

         <p>The following options are available:</p>

         <fos:options>
            <fos:option key="allow-deprecated-features">
               <fos:meaning>Indicates that deprecated URI
               features should be returned</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="omit-default-ports">
               <fos:meaning>Indicates that a port number that is the same as
               the default port for a given scheme should be omitted.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
            <fos:option key="unc-path">
               <fos:meaning>Indicates that an input URI that begins
               with two or more leading slashes should be interprted
               as a Windows Universal Naming Convention
               Path. (Specifically: that it has the <code>file:</code> scheme.)</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
         </fos:options>

         <p>This function is described as a series of transformations
         over the input string to identify the parts of a URI that are
         present. Some portions of the URI are identified by matching
         with a regular expression. This approach is designed to make
         the description clear and unambiguous; it is not implementation
         advice. Comparison of <emph>scheme</emph> and <emph>authority</emph>
         components is case insensitive.</p>

         <p>Processing begins with a <emph>string</emph> that is equal
         to the <code>$value</code>. If the <emph>string</emph> contains
         any backslashes (<code>\</code>), replace them with forward
         slashes (<code>/</code>).</p>

         <p>Strip off the fragment identifier and any query:</p>
         
         <ulist>
            <item>
         <p>If the <emph>string</emph> matches <code>^(.*?)#(.*)$</code>, the
         <emph>string</emph> is the first match group and the
         <emph>fragment</emph> is the second match group. Otherwise, the string
         is unchanged and the <emph>fragment</emph> is the empty sequence. If a
         fragment is present, it is URI decoded. If the fragment is a zero-length
         string, it is discarded and the <emph>fragment</emph> is the empty
         sequence.</p>
            </item>
            <item>
         <p>If the <emph>string</emph> matches <code>^(.*?)\?(.*)$</code>,
         the <emph>string</emph> is the first match group and the
         <emph>query</emph> is the second match group. Otherwise,
         the string is unchanged and the <emph>query</emph> is the empty
         sequence. If the query is a zero-length
         string, it is discarded and the <emph>query</emph> is the empty
         sequence.</p>
            </item>
         </ulist>

         <p>Attempt to identify the scheme:</p>

         <ulist>
            <item>
               <p>If the <emph>string</emph> matches
               <code>^([a-zA-Z][A-Za-z0-9\+\-\.]+):(.*)$</code>:</p>
               <ulist>
                  <item><p>the <emph>scheme</emph> is the first match group and</p></item>
                  <item><p>the <emph>string</emph> is the second match group.</p></item>
               </ulist>
            </item>
            <item>
               <p>Otherwise, the <emph>scheme</emph> is the empty sequence and the
               <emph>string</emph> is unchanged.</p>
            </item>
         </ulist>

         <p>If the <emph>scheme</emph> is not empty and the <emph>fragment</emph> is empty,
         <emph>absolute</emph> is true. Otherwise, <emph>absolute</emph> is the empty
         sequence. (But see the discussion of hierarchical URIs, below.)</p>

         <p>If <emph>scheme</emph> is the empty sequence or <code>file</code>:</p>
         <ulist>
            <item>
               <p>If the <emph>string</emph> matches <code>^/*([a-zA-Z][:|].*)$</code>:</p>
               <ulist>
                  <item><p>the <emph>scheme</emph> is <code>file</code> and</p></item>
                  <item><p>the <emph>string</emph> is a single slash <code>/</code> followed
                  by the first match group with the
                  second character changed to <code>:</code>, if necessary.</p></item>
               </ulist>
            </item>
            <item>
               <p>Otherwise, if <emph>unc-path</emph> is <code>true</code>:</p>
               <ulist>
                  <item><p>the <emph>scheme</emph> is <code>file</code> and</p></item>
                  <item><p>the <emph>string</emph> is unchanged.</p></item>
               </ulist>
            </item>
            <item><p>Finally, if neither of the preceding cases apply:</p>
            <ulist>
               <item><p>the <emph>scheme</emph> remains the empty sequence and</p></item>
               <item><p>the <emph>string</emph> is unchanged.</p></item>
            </ulist>
            </item>
         </ulist>

         <p>Now that the scheme, if there is one, has been identified,
         determine if the URI is hierarchical:</p>

         <ulist>
            <item>
         <p>If the <emph>scheme</emph> is known to be hierarchical, or known
         not to be hierarchical, then <emph>hierarchical</emph> is set accordingly.
         If the implementation does not know if a <emph>scheme</emph> is or is not
         hierarchical, the <emph>hierarchical</emph> setting depends on the
         <emph>string</emph>: if the <emph>string</emph> is the zero-length string,
         <emph>hierarchical</emph> is the empty sequence (<emph>i.e.</emph> not known),
         otherwise <emph>hierarchical</emph> is
         <code>true</code> if <emph>string</emph> begins with <code>/</code> and
         <code>false</code> otherwise.</p>
            </item>
         </ulist>

         <p>If the URI is not <emph>hierarchical</emph>, <emph>absolute</emph>
         is the empty sequence.</p>

         <p>Identify the remaining components according to the scheme and whether
         or not the URI is hierarchical.</p>

         <ulist>
            <item>
               <p>If the scheme is <code>file</code>:</p>
               <ulist>
                  <item>
                     <p>The <emph>authority</emph> is the empty sequence.</p>
                  </item>
                  <item>
                     <p>If <emph>unc-path</emph> is true and the string
                     matches <code>^/*(//[^/].*)$</code>: then <emph>filepath</emph>,
                     and <emph>string</emph> are both the first match group.</p>
                  </item>
                  <item>
                     <p>If the <emph>string</emph> begins <code>^//*[A-Za-z]:/</code> then
                     all but one leading slash is removed from <emph>string</emph> and the
                     <emph>filepath</emph> is the <emph>string</emph> with all leading slashes removed.</p>
                  </item>
                  <item>
                     <p>Otherwise, the <emph>filepath</emph>
                     and <emph>string</emph> are the <emph>string</emph>
                     with any sequence of leading slashes replaced by a single slash.</p>
                  </item>
               </ulist>
            </item>
            <item>
               <p>If the scheme is <code>hierarchical</code>:</p>
               <ulist>
                  <item>
                     <p>If the <emph>string</emph>
                     matches <code nobreak="true">^//([^/]+)$</code>, the <emph>authority</emph>
                     is the first match group and the <emph>string</emph> is empty.</p>
                  </item>
                  <item>
                     <p>If the <emph>string</emph>
                     matches <code nobreak="true">^//([^/]*)(/.*)$</code>, the <emph>authority</emph>
                     is the first match group and the <emph>string</emph> is the second
                     match group.</p>
                  </item>
                  <item>
                     <p>Otherwise,
                     the <emph>authority</emph> is the empty sequence
                     and the <emph>string</emph> is unchanged.</p>
                  </item>
               </ulist>
            </item>
            <item>
               <p>If the scheme is not <code>hierarchical</code>:</p>
               <ulist>
                  <item>
                     <p>The <emph>authority</emph> is the empty sequence
                     and the <emph>string</emph> is unchanged.</p>
                  </item>
               </ulist>
            </item>
         </ulist>

         <p>If the <emph>authority</emph> matches
         <code>^(([^@]*)@)(.*)(:([^:]*))?$</code>,
         then the <emph>userinfo</emph> is match group 2, otherwise
         <emph>userinfo</emph> is the empty sequence. If
         <emph>userinfo</emph> is present and contains a non-empty password, then
         <emph>userinfo</emph> is discarded and set to the empty sequence
         unless the <code>allow-deprecated-features</code> option is <code>true</code>.</p>

         <p>When parsing the <emph>authority</emph> to find the <emph>host</emph>,
         there are four possibilities: the host can be a registered name (e.g.,
         <code>example.com</code>), an IPv4 address (e.g., <code>127.0.0.1</code>),
         an IPv6 (or IPvFuture) address (e.g., <code>[::1]</code>), or an error
         if there is an open square bracket (<code>[</code>) not matched by a
         close square bracket (<code>]</code>). In a properly
         constructed RFC 3986 URI, the only place where square
         brackets may occur is around the IPv6/IPvFuture IP address.</p>

         <olist>
            <item>
               <p>If the <emph>authority</emph> matches
               <code>^(([^@]*)@)?(\[[^\]]*\])(:([^:]*))?$</code>,
               then the <emph>host</emph> is match group 3, otherwise
               </p>
            </item>
            <item>
               <p>If the <emph>authority</emph> matches
               <code>^(([^@]*)@)?\[.*$</code>
               then <errorref class="UR" code="0001"/> is raised, otherwise
               </p>
            </item>
            <item>
               <p>If the <emph>authority</emph> matches
               <code>^(([^@]*)@)?([^:]+)(:([^:]*))?$</code>,
               then the <emph>host</emph> is match group 3, otherwise
               </p>
            </item>
            <item>
               <p>the <emph>host</emph> is the empty sequence.</p>
            </item>
         </olist>

         <p>This function does not attempt to decode the components of the
         <emph>host</emph>.</p>

         <p>Similar care must be taken to match the port because an IPv6/IPvFuture
         address may contain a colon.</p>

         <ulist>
            <item>
               <p>If the <emph>authority</emph> matches
               <code>^(([^@]*)@)?(\[[^\]]*\])(:([^:]*))?$</code>,
               then the <emph>port</emph> is match group 5.
               </p>
            </item>
            <item>
               <p>Otherwise, if the <emph>authority</emph> matches
               <code>^(([^@]*)@)?([^:]+)(:([^:]*))?$</code>,
               then the <emph>port</emph> is match group 5.
               </p>
            </item>
            <item>
               <p>Otherwise, the <emph>port</emph> is the empty sequence.</p>
            </item>
         </ulist>

         <p>If the <code>omit-default-ports</code> option is <code>true</code>,  the port
         is discarded and set to the empty sequence if the port number is the same
         as the default port for the given scheme. Implementations <rfc2119>should</rfc2119>
         recognize the default ports for <code>http</code> (80), <code>https</code> (443),
         <code>ftp</code> (21), and <code>ssh</code> (22). Exactly which ports are
         recognized
         is <termref def="implementation-defined">implementation-defined</termref>.
         </p>

         <p>If the <emph>string</emph> is a zero-length string, then
         <emph>path</emph> is the empty sequence, otherwise <emph>path</emph>
         is the whole <emph>string</emph>. If the <emph>scheme</emph> is 
         the empty sequence, <emph>filepath</emph> is also the whole <emph>string</emph>.</p>

         <p>A <emph>path-segments</emph> sequence is constructed by tokenizing
         the <emph>string</emph> on <code>/</code> (solidus) and applying
         <emph>uri decoding</emph> on each token.</p>

         <note>
         <p>The <emph>path</emph> and <emph>path-segments</emph> properties both contain
         the path portion of the URI. The different formats
         only become important when the path contains encoded delimiters.</p>
         <p>Consider <code>/path%2Fsegment</code>. An application may want to decode that,
         using <code>/path/segment</code> in a database query, for example. At the same
         time, an application may wish to modify the URI and then reconstruct it.</p>

         <p>In the string form, decoding <code>%2F</code> to <code>/</code> is
         not reversible. In the <emph>path-segments</emph> form, the path is
         broken into discrete segments where the syntactic delimiters occur.
         This means the encoded delimiters can be decoded without introducing
         ambiguity: <code>("", "path/segment")</code>. In this format, the
         decoding is reversible: escape the non-syntactic delimiters before
         reconstructing the path with the syntactic ones.</p>

         <p>A consequence of constructing the <emph>path-segments</emph> this
         way is that a zero-length string appears before the first <code>/</code>,
         if the path begins with a
         <code>/</code>, after the last
         <code>/</code>, if the path ends with a
         <code>/</code>, and between consecutive
         <code>/</code> characters. (If the path consists of a single <code>/</code>,
         that <code>/</code> counts as <emph>both</emph> the first and last <code>/</code>,
         producing a segment list containing two empty strings.)</p>

         <p>The
         empty strings may seem unnecessary at first glance, but they assure
         that the path can be reconstructed by joining the segments together
         again without having to handle the presence or absence of a leading or
         trailing <code>/</code> as special cases.</p></note>

         <p>Applying <emph>uri decoding</emph> is equivalent to
         calling <function>fn:decode-from-uri</function> on the string.</p>

         <p>The <emph>query-parameters</emph> value is constructed as follows.
         Start with the empty map. Tokenize the <emph>query</emph> on
         the <code>&amp;</code> (ampersand). For each token, identify
         the <emph>key</emph> and the <emph>value</emph>. If the token
         contains an equal sign (<code>=</code>), the <emph>key</emph>
         is the string that precedes the first equal sign, uri
         decoded, and the <emph>value</emph> is the remainder
         of the token, after the first equal sign, uri decoded. If the
         token does not contain an equal sign, <emph>key</emph> is the
         empty string and the <emph>value</emph> is equal to the
         token, uri decoded. Add the <emph>key</emph>/<emph>value</emph> pair
         to the map. If the <emph>key</emph> already exists in the map, add the <emph>value</emph>
         to a list of values associated with that key. The resulting map, when all
         tokens have been processed, is the <emph>query-parameters</emph> map.</p>

         <p>If the <emph>filepath</emph> is not the empty sequence,
         it is uri decoded. On a Windows system, any
         forward slashes in the path <rfc2119>may</rfc2119> be
         replaced with backslashes.</p>

         <p>A <loc href="#uri-structure-record">uri-structure-record</loc> is returned.
         The record should be populated with only those keys that have a non-empty value (keys
         whose value is the empty sequence <rfc2119>should</rfc2119>
         be omitted).</p>

         <p>Implementations may implement additional or different rules for URIs that
         have a scheme or pattern that they recognize. An implementation might choose
         to parse <code>jar:</code> URIs with special rules, for example, since they extend the
         syntax in ways not defined by <bibref ref="rfc3986"/>. Implementations may add
         additional keys to the map. The meaning of those keys is implementation-defined.</p>
      </fos:rules>

      <fos:errors>
         <p>A dynamic error is raised <errorref class="UR" code="0001"/> if
         the URI contains an open square bracket in the authority component that
         is not followed by a close square bracket.</p>
      </fos:errors>

      <fos:notes>
         <p>Like <function>fn:resolve-uri</function>, this function handles the additional characters
         allowed in <bibref ref="rfc3987"/> IRIs in the same way that other unreserved
         characters are handled.</p>
         <p>Unlike <function>fn:resolve-uri</function>, this function is not attempting to resolve
         one URI against another and consequently, the errors that can arise under those
         circumstances do not apply here. The <function>fn:parse-uri</function> function will
         accept strings that would raise errors if resolution was attempted;
         see <function>fn:build-uri</function>.</p>
      </fos:notes>
      
<fos:examples role="wide">
  <fos:example>
    <p>In the examples that follow, keys with values that are null or the empty sequence
    are elided for editorial clarity. String literals that include an ampersand character
    are written as string templates (for example <code>`Barnes&amp;Noble`</code>) to ensure
    that the examples work in both XPath and XQuery.</p>

<fos:test>
<fos:expression><eg>parse-uri("http://qt4cg.org/specifications/xpath-functions-40/Overview.html#parse-uri")</eg></fos:expression>
<fos:result><eg>{
  "authority": "qt4cg.org",
  "fragment": "parse-uri",
  "hierarchical": true(),
  "host": "qt4cg.org",
  "path": "/specifications/xpath-functions-40/Overview.html",
  "path-segments": ("", "specifications", "xpath-functions-40", "Overview.html"),
  "scheme": "http",
  "uri": "http://qt4cg.org/specifications/xpath-functions-40/Overview.html#parse-uri"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("http://www.ietf.org/rfc/rfc2396.txt")</eg></fos:expression>
<fos:result><eg>{
  "authority": "www.ietf.org",
  "hierarchical": true(),
  "absolute": true(),
  "host": "www.ietf.org",
  "path": "/rfc/rfc2396.txt",
  "path-segments": ("", "rfc", "rfc2396.txt"),
  "scheme": "http",
  "uri": "http://www.ietf.org/rfc/rfc2396.txt"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("https://example.com/path/to/file")</eg></fos:expression>
<fos:result><eg>{
  "authority": "example.com",
  "path": "/path/to/file",
  "scheme": "https",
  "path-segments": ("", "path", "to", "file"),
  "host": "example.com",
  "hierarchical": true(),
  "absolute": true(),
  "uri": "https://example.com/path/to/file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri(
  `https://example.com:8080/path?s=%22hello world%22&amp;sort=relevance`
)</eg></fos:expression>
<fos:result><eg>{
  "authority": "example.com:8080",
  "hierarchical": true(),
  "absolute": true(),
  "host": "example.com",
  "path": "/path",
  "path-segments": ("", "path"),
  "port": 8080,
  "query": `s=%22hello world%22&amp;sort=relevance`,
  "query-parameters": {
    "s": """hello world""",
    "sort": "relevance"
  },
  "scheme": "https",
  "uri": `https://example.com:8080/path?s=%22hello world%22&amp;sort=relevance`
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("https://user@example.com/path/to/file")</eg></fos:expression>
<fos:result><eg>{
  "authority": "user@example.com",
  "hierarchical": true(),
  "absolute": true(),
  "host": "example.com",
  "path": "/path/to/file",
  "path-segments": ("", "path", "to", "file"),
  "scheme": "https",
  "uri": "https://user@example.com/path/to/file",
  "userinfo": "user"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("ftp://ftp.is.co.za/rfc/rfc1808.txt")</eg></fos:expression>
<fos:result><eg>{
  "authority": "ftp.is.co.za",
  "hierarchical": true(),
  "absolute": true(),
  "host": "ftp.is.co.za",
  "path": "/rfc/rfc1808.txt",
  "path-segments": ("", "rfc", "rfc1808.txt"),
  "scheme": "ftp",
  "uri": "ftp://ftp.is.co.za/rfc/rfc1808.txt"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("file:////uncname/path/to/file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "/uncname/path/to/file",
  "hierarchical": true(),
  "absolute": true(),
  "path": "/uncname/path/to/file",
  "path-segments": ("", "uncname", "path", "to", "file"),
  "scheme": "file",
  "uri": "file:////uncname/path/to/file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("file:///c:/path/to/file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "c:/path/to/file",
  "hierarchical": true(),
  "absolute": true(),
  "path": "/c:/path/to/file",
  "path-segments": ("", "c:", "path", "to", "file"),
  "scheme": "file",
  "uri": "file:///c:/path/to/file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("file:/C:/Program%20Files/test.jar")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "C:/Program Files/test.jar",
  "hierarchical": true(),
  "absolute": true(),
  "path": "/C:/Program%20Files/test.jar",
  "path-segments": ("", "C:", "Program Files", "test.jar"),
  "scheme": "file",
  "uri": "file:/C:/Program%20Files/test.jar"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("file:\\c:\path\to\file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "c:/path/to/file",
  "hierarchical": true(),
  "absolute": true(),
  "path": "/c:/path/to/file",
  "path-segments": ("", "c:", "path", "to", "file"),
  "scheme": "file",
  "uri": "file:\\c:\path\to\file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("file:\c:\path\to\file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "c:/path/to/file",
  "hierarchical": true(),
  "absolute": true(),
  "path": "/c:/path/to/file",
  "path-segments": ("", "c:", "path", "to", "file"),
  "scheme": "file",
  "uri": "file:\c:\path\to\file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("c:\path\to\file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "c:/path/to/file",
  "hierarchical": true(),
  "path": "/c:/path/to/file",
  "path-segments": ("", "c:", "path", "to", "file"),
  "scheme": "file",
  "uri": "c:\path\to\file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("/path/to/file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "/path/to/file",
  "hierarchical": true(),
  "path": "/path/to/file",
  "path-segments": ("", "path", "to", "file"),
  "uri": "/path/to/file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("#testing")</eg></fos:expression>
<fos:result><eg>{
  "fragment": "testing",
  "uri": "#testing"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("?q=1")</eg></fos:expression>
<fos:result><eg>{
  "query": "q=1",
  "query-parameters":{
    "q": "1"
  },
  "uri": "?q=1"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("ldap://[2001:db8::7]/c=GB?objectClass?one")</eg></fos:expression>
<fos:result><eg>{
  "authority": "[2001:db8::7]",
  "hierarchical": true(),
  "absolute": true(),
  "host": "[2001:db8::7]",
  "path": "/c=GB",
  "path-segments": ("", "c=GB"),
  "query": "objectClass?one",
  "query-parameters":{
    "": "objectClass?one"
  },
  "scheme": "ldap",
  "uri": "ldap://[2001:db8::7]/c=GB?objectClass?one"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("mailto:John.Doe@example.com")</eg></fos:expression>
<fos:result><eg>{
  "hierarchical": false(),
  "path": "John.Doe@example.com",
  "path-segments": "John.Doe@example.com",
  "scheme": "mailto",
  "uri": "mailto:John.Doe@example.com"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("news:comp.infosystems.www.servers.unix")</eg></fos:expression>
<fos:result><eg>{
  "hierarchical": false(),
  "path": "comp.infosystems.www.servers.unix",
  "path-segments": "comp.infosystems.www.servers.unix",
  "scheme": "news",
  "uri": "news:comp.infosystems.www.servers.unix"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("tel:+1-816-555-1212")</eg></fos:expression>
<fos:result><eg>{
  "hierarchical": false(),
  "path": "+1-816-555-1212",
  "path-segments": " 1-816-555-1212",
  "scheme": "tel",
  "uri": "tel:+1-816-555-1212"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("telnet://192.0.2.16:80/")</eg></fos:expression>
<fos:result><eg>{
  "authority": "192.0.2.16:80",
  "hierarchical": true(),
  "absolute": true(),
  "host": "192.0.2.16",
  "path": "/",
  "path-segments": ("", ""),
  "port": 80,
  "scheme": "telnet",
  "uri": "telnet://192.0.2.16:80/"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("urn:oasis:names:specification:docbook:dtd:xml:4.1.2")</eg></fos:expression>
<fos:result><eg>{
  "hierarchical": false(),
  "path": "oasis:names:specification:docbook:dtd:xml:4.1.2",
  "path-segments": "oasis:names:specification:docbook:dtd:xml:4.1.2",
  "scheme": "urn",
  "uri": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("tag:textalign.net,2015:ns")</eg></fos:expression>
<fos:result><eg>{
  "hierarchical": false(),
  "path": "textalign.net,2015:ns",
  "path-segments": "textalign.net,2015:ns",
  "scheme": "tag",
  "uri": "tag:textalign.net,2015:ns"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<fos:test>
<fos:expression><eg>parse-uri("tag:jan@example.com,1999-01-31:my-uri")</eg></fos:expression>
<fos:result><eg>{
  "hierarchical": false(),
  "path": "jan@example.com,1999-01-31:my-uri",
  "path-segments": "jan@example.com,1999-01-31:my-uri",
  "scheme": "tag",
  "uri": "tag:jan@example.com,1999-01-31:my-uri"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<p>This example uses the algorithm described above, not an algorithm that is
specifically aware of the <code>jar:</code> scheme.</p>
<fos:test>
<fos:expression><eg>parse-uri("jar:file:/C:/Program%20Files/test.jar!/foo/bar")</eg></fos:expression>
<fos:result><eg>{
  "hierarchical": false(),
  "path": "file:/C:/Program%20Files/test.jar!/foo/bar",
  "path-segments": ("file:", "C:", "Program Files", "test.jar!", "foo", "bar"),
  "scheme": "jar",
  "uri": "jar:file:/C:/Program%20Files/test.jar!/foo/bar"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<p>This example demonstrates that parsing the URI treats non-URI characters in
lexical IRIs as “unreserved characters”. The rationale for this is given in the
description of <function>fn:resolve-uri</function>.</p>
<fos:test>
<fos:expression><eg>parse-uri("http://www.example.org/Dürst")</eg></fos:expression>
<fos:result><eg>{
  "authority": "www.example.org",
  "hierarchical": true(),
  "absolute": true(),
  "host": "www.example.org",
  "path": "/Dürst",
  "path-segments": ("", "Dürst"),
  "scheme": "http",
  "uri": "http://www.example.org/Dürst"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<p>This example demonstrates the use of <code>|</code> instead of <code>:</code> in a Windows
path.</p>
<fos:test>
<fos:expression><eg>parse-uri("c|/path/to/file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "c:/path/to/file",
  "hierarchical": true(),
  "path": "/c:/path/to/file",
  "path-segments": ("", "c:", "path", "to", "file"),
  "scheme": "file",
  "uri": "c|/path/to/file"
}</eg></fos:result>
</fos:test>
</fos:example>

<fos:example>
<p>This example demonstrates the use of <code>|</code> instead of <code>:</code> in a Windows
path with an explicit <code>file:</code> scheme.</p>
<fos:test>
<fos:expression><eg>parse-uri("file://c|/path/to/file")</eg></fos:expression>
<fos:result><eg>{
  "filepath": "c:/path/to/file",
  "hierarchical": true(),
  "absolute": true(),
  "path": "/c:/path/to/file",
  "path-segments": ("", "c:", "path", "to", "file"),
  "scheme": "file",
  "uri": "file://c|/path/to/file"
}</eg></fos:result>
</fos:test>
</fos:example>
</fos:examples>

<!--< fos:history>
         <fos:version version="4.0">Proposed on 17 Oct 2022 to resolve
         <loc href="https://github.com/qt4cg/qtspecs/issues/72">issue #72</loc>.
         Accepted in principle on 15 Nov 2022, with some details still
         to be resolved. Updated in response to 
         <loc href="https://github.com/qt4cg/qtspecs/issues/389">issue #389</loc> and
         <loc href="https://github.com/qt4cg/qtspecs/issues/390">issue #390</loc>.
         Further updated on 13 September 2023 in response to comments from review
         in meeting 042.</fos:version>
      </fos:history>-->
      <fos:changes>
         <fos:change date="2022-10-17" PR="215 415 " issue="72 389 390"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="build-uri" prefix="fn" diff="add">
      <fos:signatures>
         <fos:proto name="build-uri" return-type="xs:string">
            <fos:arg name="parts" type-ref="uri-structure-record"
               example='{
               "scheme": "https",
               "host": "qt4cg.org",
               "port": (),
               "path": "/specifications/index.html"
               }'/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-dependent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>

      <fos:summary>
         <p>Constructs a URI from the parts provided.</p>
      </fos:summary>

      <fos:rules>
        <p>A URI is composed from a scheme, authority, path, query, and fragment.</p>

        <p>The following options are available:</p>

        <fos:options>
           <fos:option key="allow-deprecated-features">
              <fos:meaning>Indicates that deprecated URI
              features should be returned</fos:meaning>
              <fos:type>xs:boolean</fos:type>
              <fos:default>false</fos:default>
           </fos:option>
           <fos:option key="omit-default-ports">
              <fos:meaning>Indicates that a port number that is the same as
              the default port for a given scheme should be omitted.</fos:meaning>
              <fos:type>xs:boolean</fos:type>
              <fos:default>false</fos:default>
           </fos:option>
            <fos:option key="unc-path">
               <fos:meaning>Indicates that the URI represents
               a Windows Universal Naming Convention
               Path.</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
        </fos:options>

        <p>The components are derived from the contents of the
        <code>$parts</code> map. To simplify the description below, a
        value is considered to be present in the map if the relevant
        field exists and is non-empty.</p>

        <p>If the <code>scheme</code> key is present in the map,
        the URI begins with the value of that key. A URI is considered to be
        non-hierarchical if either the <code>hierarchical</code> key
        is present in the <code>$parts</code> map with the value
        <code>false</code> or if the scheme is known to be
        non-hierarchical. (In other words, schemes are hierarchical by
        default.)</p>

        <ulist>
           <item><p>If the <code>scheme</code> is
        known to be non-hierarchical, it is delimited by a trailing
        <code>:</code>.</p>
        </item>
        <item><p>Otherwise, if the <code>scheme</code> is <code>file</code> and the <code>unc-path</code>
        option is <code>true</code>, the scheme is delimited by a trailing <code>:////</code>.</p>
        </item>
        <item><p>Otherwise, the scheme is delimited by
        a trailing <code>://</code>.</p>
        </item>
        </ulist>

        <p>For simplicity of exposition, we take the
        <code>userinfo</code>, <code>host</code>, and
        <code>port</code> values from the map and imagine they are
        stored in variables with the same name. If the key is not
        present in the map, the value of the variable is set to the
        empty sequence.</p>

        <p>If <code>$userinfo</code> is non-empty and contains a
        non-empty password, then <code>$userinfo</code> is set to the
        empty sequence unless the
        <code>allow-deprecated-features</code> option is <code>true</code>.</p>

        <p>If the <code>omit-default-ports</code> option is <code>true</code>
        then the <code>$port</code> is set to the empty sequence if
        the port number is the same as the default port for the given
        scheme. Implementations <rfc2119>should</rfc2119> recognize
        the default ports for <code>http</code> (80),
        <code>https</code> (443), <code>ftp</code> (21), and
        <code>ssh</code> (22). Exactly which ports are recognized is
        <termref def="implementation-defined">implementation-defined</termref>.
        </p>

        <p>If any of <code>$userinfo</code>, <code>$host</code>, or <code>$port</code>
        exist, the following authority is added to the URI under construction:
        <eg>concat(
  if (exists($userinfo)) { $userinfo || "@" },
  $host,
  if (exists($port)) { ":" || $port }
)</eg></p>

        <p>If none of <code>userinfo</code>, <code>host</code>, or <code>port</code>
        is present, and <code>authority</code> is present, the value of the
        <code>authority</code> key is added to the URI. (In this case, no attempt
        is made to determine if a password or standard port are present,
        the <code>authority</code> value is simply added to the string.)</p>

        <p>The <function>fn:parse-uri</function> function removes
        percent-escaping when it constructs the
        <code>path-segments</code>, <code>query-parameters</code>, and
        <code>fragment</code> properties. That’s often the most
        convenient behavior but, in order to reconstruct a URI from them,
        special escaping rules apply. These rules protect delimiters
        without encoding additional characters unnecessarily.
        The rules for <code>path-segments</code>,
        <code>query-parameters</code>, and <code>fragment</code> are
        slightly different because the URI encoding conventions are
        slightly different in each case.</p>

        <p>An application with more stringent requirements can
        construct a <code>path</code> or <code>query</code> that
        satisfies the requirements and leave the
        <code>path-segments</code> and/or
        <code>query-parameters</code> keys out of the map.</p>

        <ulist>
           <item><p>If the <code>path-segments</code> key exists in
           the map, then the path is constructed from the segments. To
           construct the path, the possibly encoded segments are
           concatentated together, separated by
           <char>U+002F</char> characters.</p>

           <p>The rules for encoding the path segments are different
           for hierarchical and non-hierarchical URIs. If the URI is
           non-hierarchical, no
           encoding is performed on the segments. Otherwise,
           each segment is encoded by replacing any control characters (codepoints less than 0x20)
           and exclusively the following characters with their
           percent-escaped forms: <char>U+0020</char>, <char>U+0025</char>, 
              <char>U+002F</char>, <char>U+003F</char>,
           <char>U+0023</char>, <char>U+002B</char>,
           <char>U+005B</char>, and <char>U+005D</char>. 
              That is “<code>[#0-#20%/\?\#\+\[\]]</code>”.</p>

           <note>
              <p>Encoding is performed unless the URI is known to be non-hierarchical;
              in other words, encoding is the default. This heuristic improves the
              reliability of using <code>fn:build-uri()</code> on the output of
              <code>fn:parse-uri()</code>. (For example,
              <code>fn:parse-uri('a+b/c') => fn:build-uri()</code> will return 
              <code>a+b/c</code>.)</p>
              <p>It is necessary to avoid encoding non-hierarchical schemes because there is more
              variation in them (for example, the <code>tel:</code> scheme
              uses a “<code>+</code>” that must not be encoded). Users working with
              non-hierarchical schemes may need to address the encoding issue directly
              bearing in mind the encoding requirements of the particular schemes in use.</p>
           </note>
        </item>
        <item>
           <p>Otherwise the value of the <code>path</code> key is used.</p>
        </item>
        <item>
           <p>If neither are present, a zero-length string is used for the path.</p>
        </item>
        </ulist>

        <p>The path is added to the URI.</p>

        <p>If the <code>query-parameters</code> key exists in the map, its value
        must be a map. A sequence of strings is constructed from the values in the map.</p>

        <p>To construct the string, each <emph>key</emph> and <emph>value</emph>
        is encoded.
        The encoding performed replaces any control characters (codepoints less than 0x20)
        and exclusively the following characters with their
        percent-escaped forms: <char>U+0020</char>, <char>U+0025</char>, <char>U+003D</char>,
        <char>U+0026</char>,
        <char>U+0023</char>, <char>U+002B</char>,
        <char>U+005B</char>, and <char>U+005D</char>. That is “<code>[#0-#20%=&amp;\#\+\[\]]</code>”.
        (This differs from the path encoding in that it excludes <char>U+002F</char>
        and <char>U+003F</char> but includes <char>U+003D</char> and <char>U+0026</char>.)
        For each <emph>key</emph> and each <emph>value</emph> associated with
        that key in turn:</p>

        <ulist>
           <item><p>If the <emph>key</emph> is a zero-length string, the string constructed
           is the encoded <emph>value</emph>.</p></item>
           <item><p>Otherwise, the string constructed is the value of the
           <emph>key</emph>, encoded, followed by an equal sign (<char>U+003D</char>),
           followed by the <emph>value</emph>, encoded.</p></item>
        </ulist>

        <p>The query is constructed by joining the resulting
        strings into a single string, separated by <code>&amp;</code> (ampersand) characters.
        If the <code>query-parameters</code> key does not exist in the map, but
        the <code>query</code> key does, then the query is the value of the
        <code>query</code> key.</p>
        <p>If there is a query, it is added to the URI with
        a preceding <char>U+003F</char>.</p>

        <p>If the <code>fragment</code> key exists in the map, then
        the value of that key is encoded and added to the URI with a
        preceding <char>U+0023</char>.

        The encoding performed replaces any control characters (codepoints less than 0x20)
        and exclusively the following characters with their
        percent-escaped forms: <char>U+0020</char>, <char>U+0025</char>,
        <char>U+0023</char>, <char>U+002B</char>,
        <char>U+005B</char>, and <char>U+005D</char>. That is “<code>[#0-#20%\#\+\[\]]</code>”.
        (This differs from the path encoding in that it excludes <char>U+002F</char>
        and <char>U+003F</char>.)</p>

        <p>The resulting URI is returned.</p>
      </fos:rules>
      
      <fos:examples role="wide">
         <fos:example>
            <fos:test>
               <fos:expression><eg>build-uri({
  "scheme": "https",
  "host": "qt4cg.org",
  "port": (),
  "path": "/specifications/index.html"
})</eg></fos:expression>
               <fos:result>"https://qt4cg.org/specifications/index.html"</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <!--< fos:history>
         <fos:version version="4.0">Proposed on 17 Oct 2022 to resolve
         <loc href="https://github.com/qt4cg/qtspecs/issues/72">issue #72</loc>.
         Accepted in principle on 15 Nov 2022, with some details still
         to be resolved. Updated in response to 
         <loc href="https://github.com/qt4cg/qtspecs/issues/389">issue #389</loc> and
         <loc href="https://github.com/qt4cg/qtspecs/issues/390">issue #390</loc>.
         Further updated on 13 September 2023 in response to comments from review
         in meeting 042.</fos:version>
      </fos:history>-->
      <fos:changes>
         <fos:change date="2022-10-17" issue="72 389 390" PR="1423 1413"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   
   <fos:function name="partition" prefix="fn">
      <fos:signatures>
         <fos:proto name="partition" return-type="array(item()*)*">
            <fos:arg name="input" type="item()*" usage="navigation"/>
            <fos:arg name="split-when" type="fn(item()*, item(), xs:integer) as xs:boolean?" usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Partitions a sequence of items into a sequence of non-empty arrays containing the same items,
            starting a new partition when a supplied condition is true.</p>
      </fos:summary>
      <fos:rules>
         <p>Informally, the function starts by creating a partition containing the first item in the input sequence,
            if any. For each remaining item <var>J</var> in the input sequence,
            other than the first, it calls the supplied <code>$split-when</code> function with three 
            arguments: the contents of the current partition, the item <var>J</var>, and the current
            position in the input sequence.</p>
         <p>Each partition is a sequence of items; the function result wraps each partition as an array, and returns
            the sequence of arrays.</p>
         <p>If the <code>$split-when</code> function returns <code>true</code>, the current partition is wrapped as an array and added to the result,
            and a new current partition is created, initially containing the item <var>J</var> only. If the <code>$split-when</code> 
            function returns <code>false</code> or <code>()</code>, the item <var>J</var> is added to the current partition.</p>
  
      </fos:rules>
      <fos:equivalent style="xpath-expression">
for-each(
  $input,
  fn($item, $pos) { { 'item': $item, 'pos': $pos } }
)
=> fold-left((), fn($partitions, $pair) {
  if (empty($partitions) or $split-when(foot($partitions)?*, $pair?item, $pair?pos))
  then ($partitions, [ $pair?item ])
  else (trunk($partitions), array { foot($partitions)?*, $pair?item })
})           
      </fos:equivalent>
      <fos:notes>
         <p>The function enables a variety of positional grouping problems to be solved. For example:</p>
         <ulist>
            <item><p><code>partition($input, fn($a, $b) { count($a) eq 3 }</code>
               partitions a sequence into fixed size groups of length 3.</p></item>
            <item><p><code>partition($input, fn($a, $b) { boolean($b/self::h1) }</code>
               starts a new group whenever an <code>h1</code> element is encountered.</p></item>
            <item><p><code>partition($input, fn($a, $b) { $b lt foot($a) }</code>
               starts a new group whenever an item is encountered whose value is less than
               the value of the previous item.</p></item>
         </ulist>
         <p>The callback function is not called to process the first item in the input sequence, because this will
            always start a new partition. The first argument to the callback function (the current partition) is always
            a non-empty sequence.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>partition(
  ("Anita", "Anne", "Barbara", "Catherine", "Christine"), 
  fn($partition, $next) {
    substring(head($partition), 1, 1) ne substring($next, 1, 1)
  }
)</eg></fos:expression>
               <fos:result>[ "Anita", "Anne" ], [ "Barbara" ], [ "Catherine", "Christine" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>partition(
  (1, 2, 3, 4, 5, 6, 7),
  fn($partition, $next) { count($partition) eq 2 }
)</eg></fos:expression>
               <fos:result>[ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>partition(
  (1, 4, 6, 3, 1, 1),
  fn($partition, $next) { sum($partition) ge 5 }
)</eg></fos:expression>
               <fos:result>[ 1, 4 ], [ 6 ], [ 3, 1, 1 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>partition(
  tokenize("In the beginning was the word"), 
  fn($partition, $next) {
    sum(($partition, $next) ! string-length()) gt 10
  }
)</eg></fos:expression>
               <fos:result>[ "In", "the" ], [ "beginning" ], [ "was", "the", "word" ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>partition(
  (1, 2, 3, 6, 7, 9, 10),
  fn($partition, $next) { $next != foot($partition) + 1 }
)</eg></fos:expression>
               <fos:result>[ 1, 2, 3 ], [ 6, 7 ], [ 9, 10 ]</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>partition(
  ('a', 'b', 'c', 'd', 'e'),
  fn($all, $next, $p) { $p mod 2 = 1 }
)</eg></fos:expression>
               <fos:result>[ "a", "b" ], [ "c", "d" ], [ "e" ]</fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="125" PR="507" date="2023-05-19"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="scan-left" prefix="fn">
       <fos:signatures>
         <fos:proto name="scan-left" return-type="array(*)*">
            <fos:arg name="input" type="item()*" usage ="navigation"/>           
            <fos:arg name="init" type="item()*" usage="navigation"/>           
            <fos:arg name="action" type="fn(item()*, item()) as item()*" usage="inspection"/>   
         </fos:proto>
       </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
        <p>Produces the sequence of successive partial results from 
           the evaluation of <function>fn:fold-left</function> with the same arguments.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence of <var>N</var>+1 
            <xtermref spec="DM40" ref="dt-single-member-array">single-member arrays</xtermref>, where <var>N</var> is the number of 
         items in <code>$input</code>. For values of <code>$n</code> in the range 0 to <var>N</var>,
            the value of the single member of array <code>$n+1</code> in the result sequence is the value of the expression
            <code>fold-left( subsequence($input, 1, $n), $init, $action )</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
(0 to count($input)) 
! [fold-left(subsequence($input, 1, .), $init, $action) ]
      </fos:equivalent>
      <fos:notes>
         <p>A practical implementation is likely to compute each array in the result sequence based on the value
         of the previous item, rather than computing each item independently as implied by the specification.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>scan-left(1 to 5, 0, op('+'))</eg></fos:expression>
               <fos:result><eg>[ 0 ], [ 1 ], [ 3 ], [ 6 ], [ 10 ], [ 15 ]</eg></fos:result>
            </fos:test>
         </fos:example>         
         <fos:example>
            <fos:test>
               <fos:expression><eg>scan-left(1 to 3, 0, op('-'))</eg></fos:expression>
               <fos:result><eg>[ 0 ], [ -1 ], [ -3 ], [ -6 ]</eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>scan-left(1 to 5, 1, op('*'))</eg></fos:expression>
               <fos:result>[ 1 ], [ 1 ], [ 2 ], [ 6 ], [ 24 ], [ 120 ]</fos:result>
            </fos:test>
         </fos:example>  
         <fos:example>
            <fos:test>
               <fos:expression><eg>scan-left(1 to 3, (), fn($a, $b) { $b, $a })</eg></fos:expression>
               <fos:result><eg>[ () ], [ 1 ], [ (2, 1) ], [ (3, 2, 1) ]</eg></fos:result>
            </fos:test>
         </fos:example>           
      </fos:examples>          
      <fos:changes>
         <fos:change issue="982" PR="1296" date="2024-06-23"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>

   <fos:function name="scan-right" prefix="fn">
       <fos:signatures>
         <fos:proto name="scan-right" return-type="array(*)*">
            <fos:arg name="input" type="item()*" usage ="navigation"/>           
            <fos:arg name="init" type="item()*" usage="navigation"/>           
            <fos:arg name="action" type="fn(item(), item()*) as item()*" usage="inspection"/>   
         </fos:proto>
       </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
        <p>Produces the sequence of successive partial results from 
           the evaluation of <function>fn:fold-right</function> with the same arguments.</p>
      </fos:summary>
      <fos:rules>
         <p>The function returns a sequence of <var>N</var>+1 
            <xtermref spec="DM40" ref="dt-single-member-array">single-member arrays</xtermref>, where <var>N</var> is the number of 
         items in <code>$input</code>. For values of <code>$n</code> in the range 0 to <var>N</var>,
            the value of the single member of array <code>$n+1</code> in the result sequence is the value of the expression
            <code>fold-right( subsequence($input, count($input)-$n+1), $init, $action )</code>.</p>
      </fos:rules>
      <fos:equivalent style="xpath-expression">
(0 to count($input)) 
! [ fold-right(subsequence($input, count($input)-.+1), $init, $action) ]
      </fos:equivalent>
      <fos:notes>
         <p>A practical implementation is likely to compute each array in the result sequence based on the value
         of the previous item, rather than computing each item independently as implied by the specification.</p>
      </fos:notes>  
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>scan-right(1 to 10, 0, op('+'))</eg></fos:expression>
               <fos:result><eg>[ 55 ], [ 54 ], [ 52 ], [ 49 ], [ 45 ], [ 40 ],
[ 34 ], [ 27 ], [ 19 ], [ 10 ], [ 0 ]</eg></fos:result>
            </fos:test>
         </fos:example>         
         <fos:example>
            <fos:test>
               <fos:expression><eg>scan-right(1 to 3, 0, op('-'))</eg></fos:expression>
               <fos:result><eg>[ 2 ], [ -1 ], [ 3 ], [ 0 ]</eg></fos:result>
            </fos:test>
         </fos:example>  
         <fos:example>
            <fos:test>
               <fos:expression><eg>scan-right(1 to 5, (), fn($a, $b) { $b, $a })</eg></fos:expression>
               <fos:result><eg>[ (5, 4, 3, 2, 1) ], [ (5, 4, 3, 2) ], [ (5, 4, 3) ],
[ (5, 4) ], [ 5 ], [ () ]</eg></fos:result>
            </fos:test>
         </fos:example>
      </fos:examples>      
      <fos:changes>
         <fos:change><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
    
   <fos:function name="invisible-xml" prefix="fn">
      <fos:signatures>
         <fos:proto name="invisible-xml" return-type="fn(xs:string) as item()">
            <fos:arg name="grammar" type="(xs:string | element(Q{}ixml))?" default="()" usage="navigation"/>
            <fos:arg name="options" type="map(*)?" default="{}" note="default-on-empty"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Creates an Invisible XML parser for a grammar.</p>
      </fos:summary>
      <fos:rules>
         <p>Conceptually, an <bibref ref="invisible-xml"/> processor
         takes two arguments: a grammar and an input string. The grammar
         is a description of some format and the parser will attempt to
         interpret the input string according to that description. The parser
         returns an XML representation of the input string as parsed
         by the provided grammar. If parsing fails, it returns an XML
         representation that indicates an error occurred and may
         provide additional error information.</p>

         <p>If the function is called twice with the same arguments, it is 
         <termref def="dt-nondeterministic">nondeterministic with respect to node identity</termref>.
         </p>     

         <p>For example, the following grammar describes a date as consisting
         of a year, a month, and a day. Each are a sequence of digits and they are
         separated by hyphens:</p>

         <eg> date = year, -'-', month, -'-', day .
 year = d, d, d, d .
month = '0', d | '1', ['0'|'1'|'2'] .
  day = ['0'|'1'|'2'], d | '3', ['0'|'1'] .
   -d = ['0'-'9'] .</eg>

         <p>Using this grammar to parse “2023-10-31” will produce:</p>

         <eg><![CDATA[<date><year>2023</year><month>10</month><day>31</day></date>]]></eg>

         <p>Using this grammar to parse “2023-10-32” will produce something like this:</p>

         <eg><![CDATA[<fail xmlns:ixml='http://invisiblexml.org/NS' ixml:state='failed'>
  <line>1</line>
  <column>10</column>
  <pos>9</pos>
  <unexpected>3</unexpected>
  <permitted>'3', ['0'; '1'; '2']</permitted>
</fail>]]></eg>

         <p>The exact format of the error output will vary between implementations.
         The only required part of the output is the <code>ixml:state</code> attribute
         that contains the value <code>failed</code>.</p>

         <note><p>Careful readers will observe that the example grammar
         will parse “2023-00-00” as a date. The grammar could easily be extended to
         exclude the “00” forms for month and day, but this is only intended to be
         an illustrative example.</p></note>

         <p>The <function>fn:invisible-xml</function> function takes a grammar and
         returns a function that can be used to parse input strings. In practice,
         constructing a parser from a grammar may be an expensive operation.
         Returning a parsing function makes it easy to efficiently reuse
         a parser.</p>

         <p>The provided grammar must be a string conforming to the Invisible XML
         specification grammar or an XML representation of such a grammar.</p>

         <p>The following options are available. The <termref def="option-parameter-conventions"
               >option parameter conventions</termref> apply.</p>

         <fos:options>
            <fos:option key="fail-on-error">
               <fos:meaning>Raise an error if the parse function fails</fos:meaning>
               <fos:type>xs:boolean</fos:type>
               <fos:default>false</fos:default>
            </fos:option>
         </fos:options>

         <p>Additional, <termref def="implementation-defined"
         >implementation-defined</termref> options may be available, for example, to control
         aspects of the XML serialization, to specify the grammar start symbol,
         or to produce output formats other than XML.</p>

         <p>If <code>$grammar</code> is the empty sequence, a parser is returned
         for the Invisible XML specification grammar. This <rfc2119>should</rfc2119> be the same
         grammar that the implementation uses to parse iXML grammars. If <code>$grammar</code> is not
         empty, it <rfc2119>must</rfc2119> be a valid Invisible XML grammar.
         If it is not, <function>fn:invisible-xml</function> raises
         <code>err:FOIX0001</code>.</p>
         
         <p>The parsing function that is returned behaves as follows:</p>
         
         <olist>
            <item><p>It takes a string as input and returns an item as its result, usually an
            XML document containing the result of the parse. (The return type is <code>item()</code>
            to allow implementations to provide other sorts of results.)</p></item>
            <item><p>It is <termref
               def="dt-nondeterministic">nondeterministic with respect to node identity</termref> (that
            is, if it is called twice with the same input string, it may or may not return the same
            document node each time).</p></item>
         </olist>

         <p>If the <code>fail-on-error</code> option is
         <code>true</code>, the parsing function will raise
         <code>err:FOIX0002</code> if the input provided cannot be
         parsed successfully. Otherwise, it returns an XML representation of the
         error (rooted at a document node) as described by the <bibref ref="invisible-xml"/> 
         specification.</p>
      </fos:rules>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>invisible-xml("S=A. A='a'.")("a")</eg></fos:expression>
               <fos:result><eg><![CDATA[<S><A>a</A></S>]]></eg></fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $parser := invisible-xml("S=A. A='a'.")
let $result := $parser("b")
return $result/*/@*:state = 'failed'</eg></fos:expression>
               <fos:result>true()</fos:result>
               <fos:postamble>The returned document contains information about the error in the parsed string.</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg><![CDATA[
let $parser := invisible-xml("S=A. A='a'.", { "fail-on-error": true() })
let $result := $parser("b")
return $result
]]></eg></fos:expression>
               <fos:error-result error-code="FOIX0002"/>
            </fos:test>
         </fos:example>
      </fos:examples>
      <fos:changes>
         <fos:change issue="238 991 1281 1404" PR="791 1256 1282 1405"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="jtree" prefix="fn">
      <fos:signatures>
         <fos:proto name="jtree" return-type="jnode((), (map(*)|array(*)))">
            <fos:arg name="input" type="(map(*)|array(*))"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>nondeterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Delivers a root <xtermref spec="DM40" ref="dt-JNode"/> wrapping 
            a map or array, enabling the use of lookup expression
            to navigate a <xtermref spec="DM40" ref="dt-JTree"/> rooted at that map or array.</p>
      </fos:summary>
      <fos:rules>
         <p>The function creates a <xtermref spec="DM40" ref="dt-JNode"/>
            that wraps the supplied map or array. Specifically, it creates a root JNode
            whose <term>·jvalue·</term> property is <code>$input</code>, and whose
            <term>·jparent·</term>, <term>·jposition·</term>, and <term>·jkey·</term> 
            properties are absent.</p>
         
         <p>This has the effect that lookup expressions starting from this JNode retain
            information for subsequent navigation.</p>
         
         <p>A JNode has unique identity. If two maps or arrays <var>M1</var> and
            <var>M2</var> have the same function identity, as determined by the
            <function>function-identity</function> function, then
            <code>jtree(<var>M1</var>) is jtree(<var>M2</var>)</code> <rfc2119>must</rfc2119>
            return true: that is, the same JNode must be
            delivered for both.</p>
         
         
      </fos:rules>
      <fos:notes>
         <p>It is to some extent <termref def="implementation-defined"/>
         whether two maps or arrays have the same function identity. Processors
         <rfc2119>should</rfc2119> ensure as a minimum that when 
            a variable <code>$m</code> is bound to a map or array,
         calling <code>jtree($m)</code> more than once (with the same variable reference)
         will deliver the same JNode each time.</p>
         
         <p>The effect of the coercion rules is technically that if an existing JNode is supplied as <code>$input</code>,
         the wrapped value will be extracted, and then rewrapped as a JNode: in practice,
         this can be short-circuited by returning the supplied JNode unchanged.</p>
         
         <p>Although <function>fn:jnode</function> is available as a function for user applications
         to call explicitly, it is also invoked implicitly by some expressions, notably when
         a path expression is written in a form such as <code>$map/child::*</code>. Specifically,
         if the left-hand operand of the <code>/</code> operator is a map or array, 
            then the supplied map or array is implicitly wrapped in a JNode. </p>
         
         <p>The effect of applying <function>fn:jnode</function> to a map or array is that subsequent retrieval operations
         within the wrapped map or array return results that retain useful information about
         where the results were found. For example, consider an expression such as <code>json-doc($source)//name</code>.
      
         This expression returns a set of JNodes representing all entries in the JTree having the key <code>"name"</code>; 
         each of these JNodes contains not only the value of the relevant <code>"name"</code> entry,
            but also the key (which in this simple example is always <code>"name"</code>
            and the containing map. This means, for example, if <code>$result</code>
            is the result of the expression <code>json-doc($source)//name</code>, then:</p>
         
         <ulist>
            <item><p><code>$result/../ssn</code> locates the map that contained each
               <code>name</code>, and returns the value of the <code>ssn</code> entry in that map.</p></item>
            <item><p><code>$result/ancestor::course</code> returns any
            <code>course</code> entries in containing maps.</p></item>
            <item><p><code>$result/ancestor::* => jkey() </code> returns a sequence of map keys and array index
            values representing the location of the found entries within the JSON structure.</p></item>
  
         </ulist>
         
         <p>An alternative way of wrapping a map or array, rather than calling <code>jtree($X)</code>,
         is to use the path expression <code>$X/.</code>.</p>
         
         <p>There are two situations where a map or array is implicitly wrapped in a JNode:</p>
         
         <ulist>
            <item><p>When the value of the left-hand operand of the <code>/</code> operator
            includes a map or array;</p></item>
            <item><p>When the context value for evaluation of an <code>AxisStep</code>
            includes a map or array.</p></item>
         </ulist>
         
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression>jtree([ "a", "b", "c" ])/*[1]/../*[last()] => string()</fos:expression>
               <fos:result>"c"</fos:result>
               <fos:postamble>The call on <code>fn:tree</code> would happen automatically</fos:postamble>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression>jtree([ "a", "b", "c", "d" ])/* =!> jkey()</fos:expression>
               <fos:result>1, 2, 3, 4</fos:result>
            </fos:test>
         </fos:example>
         <fos:example>
            <fos:test>
               <fos:expression><eg>let $data := {
  "fr": { "capital": "Paris", "languages": [ "French" ] }, 
  "de": { "capital": "Berlin", "languages": [ "German" ] }
}
return jtree($data)//languages[. = 'German']/../capital =!> string()</eg></fos:expression>
               <fos:result>"Berlin"</fos:result>
            </fos:test>
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="2025" PR="2031" date="2025-06-12"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="jkey" prefix="fn">
      <fos:signatures>
         <fos:proto name="jkey" return-type="xs:anyAtomicType?">
            <fos:arg name="input" type="jnode()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <term>·jkey·</term> property of a JNode.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>If <code>$input</code> is a root JNode (one in which the <term>·jkey·</term> property is
            absent), the function returns the empty sequence.</p>
         <p>Otherwise, the function returns the <term>·jkey·</term> property of <code>$input</code>.
         In the case where the parent JNode wraps a map, this will be the key of the relevant entry
         within that map; in the case where the parent JNode wraps an array, it will be the 1-based
         index of the relevant member of the array.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/>.</p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>jnode()?</code>, 
                  type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>
      </fos:errors>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
let $array := [ 1, 3, 4.5, 7, "eight", 10 ]
return $array/jnode(*, xs:integer) =!> jkey()
               </eg></fos:expression>
               <fos:result>1, 2, 4, 6</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
let $map := { 'Mo': 'Monday', 'Tu': 'Tuesday', 'We': 'Wednesday' }
return $map/child::get(("Mo", "We", "Fr", "Su")) =!> jkey()
               </eg></fos:expression>
               <fos:result>"Mo", "We"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
let $array := [ [ 4, 18 ], [ 30, 4, 22 ] ]
return $array/descendant::*[. > 25]/ancestor-or-self::* =!> jkey()
               </eg></fos:expression>
               <fos:result>2, 1</fos:result>
            </fos:test>
         </fos:example>
         
      </fos:examples>
      
      <fos:changes>
         <fos:change issue="2025" PR="2031" date="2025-06-12"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="jposition" prefix="fn">
      <fos:signatures>
         <fos:proto name="jposition" return-type="xs:integer?">
            <fos:arg name="input" type="jnode()?" default="." usage="inspection"/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <term>·jposition·</term> property of a JNode.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>If <code>$input</code> is a root JNode (one in which the <term>·jposition·</term> property is
            absent), the function returns the empty sequence.</p>
         <p>Otherwise, the function returns the <term>·jposition·</term> property of <code>$input</code>.
            The value of this property will be 1 (one) except in cases where 
            the value of an entry in a map, or a member in an array, is a sequence that contains
            multiple items including maps and/or arrays; in such cases
            the position will be the 1-based position of the relevant map or array.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/>.</p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>jnode()?</code>, 
                  type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>
      </fos:errors>
      <fos:notes>
         <p>This function is relevant only when there are maps whose entries are multi-item
            sequences that include maps and arrays, or arrays whose members include
            such multi-item sequences.
         Such structures are uncommon, and never arise from parsing of JSON source text.
         It is generally best to avoid such structures by using arrays rather than sequences
         within array and map content; apart from other considerations, this allows the
         data to be serialized in JSON format.</p>
         <p>If an entry within a map, or a member of an array, contains a sequence of items
         that mixes arrays and maps with other content (for example the array
          <code>[1, 2, ([1,2], [3,4], 5))</code>, then a lookup using the
            child axis will only construct JNodes in respect of those items that are
            non-empty maps or arrays. This may leave gaps in the position numbering sequence,
            as illustrated in the examples below.</p>
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
let $input := {
   "a": [ 10, 20, 30 ], 
   "b": ([ 40, 50, 60 ], [], 0, [ 70, 80, (90, 100) ])
}
return $input/b/* ! { "position": jposition(), "index": jkey(), "value": jvalue() }
               </eg></fos:expression>
               <fos:result><eg>
{ "position": 1, "index": 1, "value": 40 },
{ "position": 1, "index": 2, "value": 50 },
{ "position": 1, "index": 3, "value": 60 },
{ "position": 4, "index": 1, "value": 70 },
{ "position": 4, "index": 2, "value": 80 },
{ "position": 4, "index": 3, "value": (90, 100) }</eg></fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
let $input := {
   "a": { "x": 10, "y": 20, "z": 30 }, 
   "b": ({ "x": 40, "y": 50, "z": 60 }, {}, { "x": 70, "y": 80, "z": (90, 100) })
}
return $input/b/* ! { "position": jposition(), "key": jkey(), "value": jvalue() }
               </eg></fos:expression>
               <fos:result><eg>
{ "position": 1, "key": "x", "value": 40 },
{ "position": 1, "key": "y", "value": 50 },
{ "position": 1, "key": "z", "value": 60 },
{ "position": 3, "key": "x", "value": 70 },
{ "position": 3, "key": "y", "value": 80 },
{ "position": 3, "key": "z", "value": (90, 100) }</eg></fos:result>
            </fos:test>

            
         </fos:example>
         
      </fos:examples>
      
      <fos:changes>
         <fos:change issue="2025" PR="2031" date="2025-06-12"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
   <fos:function name="jvalue" prefix="fn">
      <fos:signatures>
         <fos:proto name="jvalue" return-type="item()*">
            <fos:arg name="input" type="jnode()?" default="."/>
         </fos:proto>
      </fos:signatures>
      <fos:properties>
         <fos:property>deterministic</fos:property>
         <fos:property>context-independent</fos:property>
         <fos:property>focus-independent</fos:property>
      </fos:properties>
      <fos:summary>
         <p>Returns the <term>·jvalue·</term> property of a JNode.</p>
      </fos:summary>
      <fos:rules>
         <p>If <code>$input</code> is the empty sequence, the function returns the empty sequence.</p>
         <p>Otherwise, the function returns the <term>·jvalue·</term> property of <code>$input</code>.</p>
      </fos:rules>
      <fos:errors>
         <p>The following errors may be raised when <code>$node</code> is omitted:</p>
         <ulist>
            <item>
               <p>If the context value is <xtermref ref="dt-absent" spec="DM40"
                     >absent</xtermref>,
                  type error <xerrorref spec="XP"
                     class="DY" code="0002" type="type"/>.</p>
            </item>
            <item>
               <p>If the context value is not an instance of the sequence type <code>jnode()?</code>, 
                  type error <xerrorref spec="XP" class="TY"
                     code="0004" type="type"/>.</p>
            </item>
         </ulist>
      </fos:errors>
      <fos:notes>
         <p>In many cases it is unnecessary to make an explicit call on <code>jvalue</code>, because
         the coercion rules will take care of this automatically. For example, in an expression
         such as <code>$X / descendant::name [matches(., '^J')]</code>, the call on
         <function>matches</function> is supplied with a JNode as its first argument; atomization
         ensures that the actual value being passed to the first argument of <function>matches</function>
            is the atomized value of the 
          <term>·jvalue·</term> property.</p>
         <p>Other examples where the <term>·jvalue·</term> of a JNode is extracted automatically
         include:</p>
         
         <ulist>
            <item><p>Any context where the required type is an atomic value, for example
            arithmetic operations, value comparisons and general comparisons, and calls
            on functions that expect an atomic value.</p></item>
            <item><p>Any context where the required type is a map or array, for example
            the first argument of functions such as <function>map:size</function>
               or <code>array:size</code>, a free-standing expression within a map
               constructor such as <code>map{ $jnode }</code>, the constructs
            <code>for member</code> and <code>for key/value</code>, the left-hand
            operand of the lookup operator <code>?</code> (or the context value
            in the case of a unary lookup operator), and the operand of a map/array
            filter expression <code>$jnode?[predicate]</code>.</p></item>
         </ulist>
         <p>Notable places where the <term>·jvalue·</term> is <emph>not</emph>
         automatically extracted include:</p>
         <ulist>
            <item><p>When computing the effective boolean
         value. As with XNodes, writing <code>if ($array/child::*[1]) ...</code> tests for the existence
         of a child, it does not test its value. To test its value, write
         <code>if (jvalue($array/child::*[1])) ...</code>,
         or equivalently <code>if (xs:boolean($array/child::*[1])) ...</code>.</p></item>
            <item><p>When calling functions that accept arbitrary sequences, such as
            <function>count</function> or <function>deep-equal</function>.</p></item>
         </ulist>
         <p>It is possible (though probably unwise) to construct a JNode whose <term>·jvalue·</term>
         property itself contains another JNode. For example, the expression 
         <code>jtree([jtree([]), jtree([])])</code> creates a JNode whose <term>·jvalue·</term>
         is an array of JNodes, and applying the <code>child</code> axis to this JNode will
         return a sequence of two JNodes that themselves have further JNodes as their content.
         The <function>jvalue</function> returns these contained JNodes, it does not
         recursively extract their content.</p>
         
      </fos:notes>
      <fos:examples>
         <fos:example>
            <fos:test>
               <fos:expression><eg>
let $array := [ 1, 3, 4.5, 7, "eight", 10 ]
return $array/jnode(*, xs:integer) =!> jvalue()
               </eg></fos:expression>
               <fos:result>1, 3, 7, 10</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
let $map := { 'Mo': 'Monday', 'Tu': 'Tuesday', 'We': 'Wednesday' }
return $map/child::get(("Mo", "We", "Fr", "Su")) =!> jvalue()
               </eg></fos:expression>
               <fos:result>"Monday", "Wednesday"</fos:result>
            </fos:test>
            <fos:test>
               <fos:expression><eg>
let $array := [ [ 4, 18 ], [ 30, 4, 22 ] ], [ 30, 4, 22 ]
return $array/descendant::*[. > 25][1]/ancestor-or-self::* =!> jvalue()</eg></fos:expression>
               <fos:result>[ [ 4, 18 ], [ 30, 4, 22 ] ], [ 30, 4, 22 ]</fos:result>
            </fos:test>
         </fos:example>
         
      </fos:examples>
      <fos:changes>
         <fos:change issue="2025" PR="2031" date="2025-06-12"><p>New in 4.0</p></fos:change>
      </fos:changes>
   </fos:function>
   
</fos:functions>
