<?xml version="1.0" encoding="UTF-8"?>
<fos:functions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ex="http://expath.org/ns/xmlspec"
    xmlns:fos="http://www.w3.org/xpath-functions/spec/namespace"
    xmlns:doc="http://jwlresearch.net/2012/doc"
    xsi:schemaLocation="http://www.w3.org/xpath-functions/spec/namespace fos.xsd">

  <fos:global-variables>
    <fos:variable id="v-expath-irrelevant" name="irrelevant" select="()"/>
  </fos:global-variables>

  <fos:function name="exists" prefix="file">
    <fos:signatures>
      <fos:proto name="exists" return-type="xs:boolean">
        <fos:arg type="xs:string" name="path"/>
      </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>Tests if a file or directory exists.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns <code>true</code> if <code>$path</code> points to an existing file or directory,
        <code>false</code> otherwise.</p>
      <p>On a UNIX-based system, the root and the volume roots are considered directories.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:exists('.')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:exists('/')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="is-dir" prefix="file">
    <fos:signatures>
      <fos:proto name="is-dir" return-type="xs:boolean">
        <fos:arg type="xs:string" name="path"/>
      </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>Tests if <code>$path</code> points to a directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns <code>true</code> if <code>$path</code> points to an existing directory
        as defined in <bibref ref="ieee1003.1-2024"/> (no regular file, no symbolic link,
        no other operating-system specific file type).
        Otherwise, it returns <code>false</code>.</p>
      <p>On a UNIX-based system, the root and the volume roots are considered directories.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:is-dir('.')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:is-dir('/')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="is-file" prefix="file">
    <fos:signatures>
      <fos:proto name="is-file" return-type="xs:boolean">
        <fos:arg type="xs:string" name="path"/>
      </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>Tests if <code>$path</code> points to a regular file.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns <code>true</code> if <code>$path</code> points to an existing regular file
        as defined in <bibref ref="ieee1003.1-2024"/> (no directory, no symbolic link,
        no other operating-system specific file type).
        Otherwise, it returns <code>false</code>.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:is-file('.')</fos:expression>
          <fos:result>false()</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:is-file('/')</fos:expression>
          <fos:result>false()</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="is-absolute" prefix="file">
    <fos:signatures>
      <fos:proto name="is-absolute" return-type="xs:boolean">
        <fos:arg type="xs:string" name="path"/>
      </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>Tests if <code>$path</code> is absolute.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns <code>true</code> if <code>$path</code> is absolute,
        <code>false</code> otherwise.</p>
      <p>A path is absolute if it contains all the components necessary to identify a file location,
         without reference to a current drive or a current working directory.</p>
      <note>
        <p>All UNC file names are absolute.</p>
        <p>The function may return a different result for the same path on a Windows and a
           UNIX-based system.</p>
      </note>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:is-absolute('abc')</fos:expression>
          <fos:result>false()</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:is-absolute('/')</fos:expression>
          <fos:result narrative="true">Returns <code>true</code> on a UNIX-based system and
             <code>false</code> on a Windows system.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2024-07-02"><p>New in 4.0.</p></fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="last-modified" prefix="file">
    <fos:signatures>
      <fos:proto name="last-modified" return-type="xs:dateTime">
        <fos:arg type="xs:string" name="path"/>
      </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>Returns the last modification time of a file or directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns an <code>xs:dateTime</code> item representing the last modification of
        a file or directory.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:last-modified('.')</fos:expression>
          <fos:result narrative="true">Returns the last modification time of the
          <termref def="current-working-dir"/>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:last-modified(file:base-dir())</fos:expression>
          <fos:result narrative="true">Returns the last modification time of the
            <termref def="base-dir"/>.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="size" prefix="file">
    <fos:signatures>
      <fos:proto name="size" return-type="xs:integer">
        <fos:arg type="xs:string" name="path"/>
        <fos:arg type="xs:boolean?" default="false()" name="recursive"/>
      </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>Returns the size of a file or directory.</p>
    </fos:summary>
    <fos:rules>
      <p>
        If <code>$path</code> points to a file, returns the byte size of this file.
        Otherwise, if it points to a directory, returns either <code>0</code> or,
        if <code>$recursive</code> is <code>true</code>, the aggregated size of all files and
        subdirectories.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:size('.')</fos:expression>
          <fos:result>0</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:size('/')</fos:expression>
          <fos:result>0</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2025-07-07">
        <p><code>$recursive</code> parameter added.</p>
      </fos:change>
   </fos:changes>
  </fos:function>

  <fos:function name="append" prefix="file">
    <fos:signatures>
      <fos:proto name="append" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="item()*" name="value"/>
        <fos:arg type="(element(output:serialization-parameters) | map(*))?" default="()" name="options"/>
      </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>Appends a serialized value to a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Serializes a value and appends the resulting string to a file.
        If the file pointed to by <code>$file</code> does not exist,
        a new file will be created.</p>
      <p>
        The <code>$options</code> argument controls the way how <code>$value</code> is serialized.
        The semantics are the same as for <xspecref spec="FO40" ref="func-serialize"/>.
        In contrast to <code>fn:serialize</code>, the encoding stage will not be skipped by
        this function.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified file does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test spec="XQuery">
          <fos:expression><![CDATA[file:append('fragments.xml', <fragment/>)]]></fos:expression>
          <fos:result narrative="true">Appends a serialized element node to the file
            <code>fragments.xml</code>. The file is created if it does not already exist.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:append('snippets.json', { 'one': 1 }, { 'method': 'json' })</fos:expression>
          <fos:result narrative="true">Serializes a map as JSON and appends the resulting string to the file
            <code>snippets.json</code>.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2025-07-07">
        <p><code>$options</code> can now be a map, in alignment with <code>fn:serialize</code>.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="append-binary" prefix="file">
    <fos:signatures>
      <fos:proto name="append-binary" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="xs:base64Binary" name="value"/>
      </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>Appends binary data to a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Appends the binary data of an <code>xs:base64Binary</code> item to a file.
        If the file pointed to by <code>$file</code> does not exist, a new file will be
        created.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:append-binary('data.bin', xs:hexBinary('414243'))</fos:expression>
          <fos:result narrative="true">Appends the bytes <code>0x44</code>, <code>0x43</code> and <code>0x41</code>
            to the file <code>data.bin</code>.
            The file is created if it does not already exist.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="append-text" prefix="file">
    <fos:signatures>
      <fos:proto name="append-text" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="xs:string" name="value"/>
        <fos:arg type="xs:string?" default="'UTF-8'" name="encoding"/>
      </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>Appends a string to a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Appends a string to a file.
        If the file pointed to by <code>$file</code> does not exist, a new file will be
        created.</p>
      <p>If no encoding is supplied, <code>UTF-8</code> is used as output encoding.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="unknown-encoding"/> is raised if the specified encoding
        is invalid or not supported by the implementation.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:append-text('todos.txt', 'clean up')</fos:expression>
          <fos:result narrative="true">Appends a string to the file <code>todos.txt</code>.
            The file is created if it does not already exist.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="append-text-lines" prefix="file">
    <fos:signatures>
      <fos:proto name="append-text-lines" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="xs:string*" name="lines"/>
        <fos:arg type="xs:string?" default="'UTF-8'" name="encoding"/>
      </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>Appends a sequence of strings to a file, each followed by the operating-system specific
        newline character.</p>
    </fos:summary>
    <fos:rules>
      <p>Appends a sequence of strings to a file, each followed by the operating-system specific
        newline character.
        If the file pointed to by <code>$file</code> does not exist, a new file will be created.</p>
      <p>If no encoding is supplied, <code>UTF-8</code> is used as output encoding.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="unknown-encoding"/> is raised if the specified encoding
        is invalid or not supported by the implementation.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:append-text-lines('numbers.txt', (1 to 5) ! string())</fos:expression>
          <fos:result narrative="true">Appends the string representation of the integers 1 to 5 to the file
            <code>numbers.txt</code>. The file is created if it does not already exist.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="copy" prefix="file">
    <fos:signatures>
      <fos:proto name="copy" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="source"/>
        <fos:arg type="xs:string" name="target"/>
      </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>Copies a file or a directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Copies a file or a directory given a source and a target path/URI.
        The following rules apply if <code>$source</code> points to a file:</p>
      <olist>
        <item>
          <p>if <code>$target</code> does not exist, it will be created.</p>
        </item>
        <item>
          <p>if <code>$target</code> is a file, it will be overwritten.</p>
        </item>
        <item>
          <p>if <code>$target</code> is a directory, the file will be created in that
            directory with the name of the source file. If a file already exists, it
            will be overwritten.</p>
        </item>
      </olist>
      <p>Otherwise, if <code>$source</code> points to a directory:</p>
      <olist>
        <item>
          <p>if <code>$target</code> does not exist, it will be created as directory, and
            all files of the source directory are copied to this directory with their
            existing local names.</p>
        </item>
        <item>
          <p>if <code>$target</code> is a directory, the source directory with all its
            files will be copied into the target directory. At each level, if a file
            already exists in the target with the same name as in the source, it is
            overwritten. If a directory already exists in the target with the same name
            as in the source, it is not removed, it is recursed in place.
            If it does not exist, it is created before recursing.</p>
        </item>
      </olist>
      <p>Other cases will result in one of the errors listed below.</p>
      <p>The function returns the empty sequence if the operation is successful.
        No rollback to the original state will be possible if an error occurs during the operation.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="exists"/> is raised if the specified source path points to a
        directory and target path points to an existing file.</p>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified source path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified source path points to a
        file and the target path points to a directory in which a subdirectory exists
        with the name of the source file.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:copy('a.txt', 'b.txt')</fos:expression>
          <fos:result narrative="true">Creates a copy of the file <code>a.txt</code> in the
            same directory, named <code>b.txt</code>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:copy('a.txt', '../')</fos:expression>
          <fos:result narrative="true">Creates a copy of the file <code>a.txt</code> with the same name
            in the parent directory.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:copy('dir/', 'dir2/')</fos:expression>
          <fos:result narrative="true">Creates a recursive copy of the directory <code>dir</code>
            in the <termref def="current-working-dir"/>, named <code>dir2</code>. If
            <code>dir2</code> already exists, the contents of <code>dir</code> will be copied
            into that directory.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="create-dir" prefix="file">
    <fos:signatures>
      <fos:proto name="create-dir" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="dir"/>
      </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>Creates a directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Creates a directory unless it already exists. The operation will also create
        non-existing parent directories.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="exists"/> is raised if the specified path, or any of
        its parent directories, points to an existing file.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:create-dir('examples')</fos:expression>
          <fos:result narrative="true">Creates a directory named <code>examples</code> in the
            <termref def="current-working-dir"/>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:create-dir('/')</fos:expression>
          <fos:result narrative="true">Does nothing, as the root directory already exists.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="create-temp-dir" prefix="file">
    <fos:signatures>
      <fos:proto name="create-temp-dir" return-type="xs:string">
        <fos:arg type="xs:string?" default="()" name="prefix"/>
        <fos:arg type="xs:string?" default="()" name="suffix"/>
        <fos:arg type="xs:string?" default="()" name="dir"/>
      </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>Creates a temporary directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Creates a temporary directory with an optional <code>$prefix</code> and
        <code>$suffix</code> in the filename, and returns the full path to the created directory.
        The path will point to a directory that did not exist before the function was called.</p>
      <p>If <code>$dir</code> is omitted or an empty sequence, the directory will be created
        inside the operating-system specific default temporary-file directory.</p>
      <note>
        <p>The created directory will not be deleted automatically after query execution.</p>
      </note>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the specified directory does not
        exist or points to a file.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:parent(file:create-temp-dir()) = file:temp-dir()</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression><eg>file:create-temp-dir(dir := file:base-dir())</eg></fos:expression>
          <fos:result narrative="true">Creates a temporary directory in the <termref def="base-dir"/> or,
            if it is undefined, in the default temporary-file directory.</fos:result>
        </fos:test>
        <fos:test spec="XQuery">
          <fos:expression><eg>
let $dir := file:create-temp-dir()
return try {
  file:write($dir || 'tmp.data', 1 to 10)
} finally {
  file:delete($dir, true())
}
          </eg></fos:expression>
          <fos:result narrative="true">Creates a temporary directory, writes a file into that directory, and
            deletes it again.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2025-07-07">
        <p>All parameters are optional now.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="create-temp-file" prefix="file">
    <fos:signatures>
      <fos:proto name="create-temp-file" return-type="xs:string">
        <fos:arg type="xs:string?" default="()" name="prefix"/>
        <fos:arg type="xs:string?" default="()" name="suffix"/>
        <fos:arg type="xs:string?" default="()" name="dir"/>
      </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>Creates a temporary file.</p>
    </fos:summary>
    <fos:rules>
      <p>Creates an empty temporary file with an optional <code>$prefix</code> and
        <code>$suffix</code> in the filename, and returns the full path to the created file.
        The path will point to a file that did not exist before the function was called.</p>
      <p>If <code>$dir</code> is omitted or an empty sequence, the file will be created inside
        the operating-system specific default temporary-file directory.</p>
      <note>
        <p>The created file will not be deleted automatically after query execution.</p>
      </note>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the specified does not exist or
        points to a file.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:create-temp-file(suffix := '.txt')</fos:expression>
          <fos:result narrative="true">Creates a file with the suffix <code>.txt</code> in the
            temporary-file directory.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2025-07-07">
        <p>All parameters are optional now.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="delete" prefix="file">
    <fos:signatures>
      <fos:proto name="delete" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="path"/>
        <fos:arg type="xs:boolean?" default="false()" name="recursive"/>
      </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>Deletes a file or a directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Deletes a file or a directory from the file system if it exists:</p>
      <ulist>
        <item>
          <p>If <code>$path</code> points to a file, the file is deleted.</p>
        </item>
        <item>
          <p>Otherwise, if <code>$path</code> points to a directory, then:</p>
          <ulist>
            <item>
              <p>if it is non-empty and <code>$recursive</code> is <code>false</code>,
                 an error is raised.</p>
            </item>
            <item>
              <p>Otherwise, the directory and all its contents are deleted recursively.</p>
            </item>
          </ulist>
        </item>
        <item>
          <p>Otherwise, nothing happens.</p>
        </item>
      </ulist>
      <p>The function returns the empty sequence if the operation is successful.</p>
      <note>
        <p>No rollback to the original state will be possible if an error occurs during the
           operation.</p>
      </note>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        non-empty directory and if the deletion is not recursive.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:delete('list.txt')</fos:expression>
          <fos:result narrative="true">Deletes the file <code>list.txt</code> from the
            <termref def="current-working-dir"/>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:delete('examples', true())</fos:expression>
          <fos:result narrative="true">Deletes the file or directory <code>example</code> and (if available)
            all subdirectories.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2547" PR="2548" date="2026-03-22">
        <p>Non-existing paths are now ignored.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="list" prefix="file">
    <fos:signatures>
      <fos:proto name="list" return-type="xs:string*">
        <fos:arg type="xs:string" name="dir"/>
        <fos:arg type="xs:boolean?" default="false()" name="recursive"/>
        <fos:arg type="xs:string?" default="()" name="pattern"/>
      </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>Lists all files and directories in a given directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Lists all files and directories in a given directory.
        In contrast to is <loc href="#func-file-children">file:children</loc>,
        the returned paths are relative to the supplied directory <code>$dir</code>.
        The order of the items in the resulting sequence is not defined.
        The references to the specified directory and its parent directory
        (<code>.</code> and <code>..</code>) are not returned.</p>
      <p>If <code>$recursive</code> is <code>true</code>, all directories and files will be returned
        that are found while recursively traversing the given directory.
        Otherwise, only the contents of the specified directory will be returned.</p>
      <p>The <code>$pattern</code> argument is used to define a name pattern in the glob syntax.
        If supplied, only the paths of the files and directories whose names are matching the pattern
        will be returned.</p>
      <p>An implementation must support at least the following glob syntax characters:</p>
      <ulist>
        <item>
          <p><code>*</code> for matching any number of unknown characters and</p>
        </item>
        <item>
          <p><code>?</code> for matching one unknown character.</p>
        </item>
      </ulist>
      <note>
        <p>A related function is <loc href="#func-file-children">file:children</loc>.</p>
      </note>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the specified path does not point
        to an existing directory.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:list('.')</fos:expression>
          <fos:result narrative="true">Returns the names of all files in the
            <termref def="current-working-dir"/>.</fos:result>
        </fos:test>
      </fos:example>
      <fos:example>
        <fos:test>
          <fos:expression>file:list('.', pattern := '*.zip')</fos:expression>
          <fos:result narrative="true">Returns the names of archive files in the
            <termref def="current-working-dir"/>.</fos:result>
        </fos:test>
      </fos:example>
      <fos:example>
        <fos:test>
          <fos:expression><eg>
let $root := '/path/to/files/'
for $file in file:list($root, true(), '*.txt')
let $path := file:resolve-path($file, $root)
where file:size($path) > 1000000
return file:read-text($path)
          </eg></fos:expression>
          <fos:result narrative="true">Returns the contents of large text files found in a specific
            directory and its subdirectories.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2025-07-07">
        <p><code>$pattern</code> can now be supplied without supplying <code>$recursive</code>.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="list-roots" prefix="file">
    <fos:signatures>
      <fos:proto name="list-roots" return-type="xs:string*"/>
    </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>Lists all root directories of the file system.</p>
    </fos:summary>
    <fos:rules>
      <p>Lists all root directories of the file system:</p>
      <ulist>
        <item>
          <p>On a Windows system, root directories are usually the letters of the
            currently available drives, followed by a colon and a backslash
            (for example, <code>C:\</code> and <code>D:\</code>).</p>
        </item>
        <item>
          <p>On a UNIX-based system, it is usually a single slash, denoting the root directory.</p>
        </item>
      </ulist>
      <note>
        <p>Dynamically available UNC file names are not returned by this function.</p>
      </note>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:list-roots('/')</fos:expression>
          <fos:result narrative="true">A single slash as result indicates a UNIX-based system.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2024-07-02"><p>New in 4.0.</p></fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="move" prefix="file">
    <fos:signatures>
      <fos:proto name="move" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="source"/>
        <fos:arg type="xs:string" name="target"/>
      </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>Moves a file or a directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Moves a file or a directory given a source and a target path/URI.
        The following rules apply if <code>$source</code> points to a file:</p>
      <olist>
        <item>
          <p>if <code>$target</code> does not exist, it will be created.</p>
        </item>
        <item>
          <p>if <code>$target</code> is a file, it will be overwritten.</p>
        </item>
        <item>
          <p>if <code>$target</code> is a directory, the file will be created in that
            directory with the name of the source file. If a file already exists, it
            will be overwritten.</p>
        </item>
      </olist>
      <p>Otherwise, if <code>$source</code> points to a directory:</p>
      <olist>
        <item>
          <p>if <code>$target</code> does not exist, it will be created as directory, and
            all files of the source directory are moved to this directory with their
            existing local names.</p>
        </item>
        <item>
          <p>if <code>$target</code> is a directory, the source directory with all its
            files will be moved into the target directory. If the target directory
            contains a directory with the same name as the source,
            the error <errorref spec="FILE40" code="is-dir"/> is raised.</p>
        </item>
      </olist>
      <p>Other cases will result in one of the errors listed below.</p>
      <p>The function returns the empty sequence if the operation is successful.
        No rollback to the original state will be possible if an error occurs during the operation.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified source
          path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="exists"/> is raised if the specified source path points to a
        directory and target path points to an existing file.</p>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified source path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified target path points to a
        directory in which a subdirectory exists with the name of the source.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:move('a.txt', 'b.txt')</fos:expression>
          <fos:result narrative="true">Renames <code>a.txt</code> to <code>b.txt</code>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:move('a.txt', '../')</fos:expression>
          <fos:result narrative="true">Moves the file <code>a.txt</code> to the parent directory.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:move('dir/', 'dir2/')</fos:expression>
          <fos:result narrative="true">Renames <code>dir</code> to <code>dir2</code>. If <code>dir2</code>
          already exists, moves the source directory into that directory.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="read-binary" prefix="file">
    <fos:signatures>
      <fos:proto name="read-binary" return-type="xs:base64Binary">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="xs:integer?" default="0" name="offset"/>
        <fos:arg type="xs:integer?" default="()" name="length"/>
      </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>Returns the binary content of a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the content of a file as an <code>xs:base64Binary</code> item.</p>
      <p>Chunks of a file can be read by supplying <code>$offset</code> and <code>$length</code>.
        If no value is supplied for <code>$length</code>, all remaining bytes will be read.
        If only <code>$length</code> is specified, the offset is <code>0</code>.
      </p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="out-of-range"/> is raised if the specified offset or length
        value is negative, or if the value would exceed the file bounds.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:read-binary('data.bin') eq xs:hexBinary('41')</fos:expression>
          <fos:result narrative="true">Returns <code>true</code> if the file <code>data.bin</code>
            contains the single byte <code>0x41</code>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:read-binary('data.bin', file:size($path) - 1, 1)</fos:expression>
          <fos:result narrative="true">Returns the last byte of the file <code>data.bin</code>.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2025-07-07">
        <p><code>$length</code> can now be supplied without supplying <code>$offset</code>.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="read-text" prefix="file">
    <fos:signatures>
      <fos:proto name="read-text" return-type="xs:string">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg name="options" type="(xs:string | map(*))?" default="()"/>
      </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>Returns the content of a file as a string.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the content of a file in its string representation.
        Newlines are normalized: Any <char>U+000D</char> character, optionally followed by
        a <char>U+000A</char> character, is converted to a single <char>U+000A</char> character.</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 <xtermref spec="FO40" ref="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>"UTF-8"</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 <xtermref spec="FO40" ref="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>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="unknown-encoding"/> is raised if the specified encoding
        is invalid or not supported by the implementation.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>contains(file:read-text('todos.txt'), 'push forward')</fos:expression>
          <fos:result narrative="true">Returns <code>true</code> if the file <code>todos.txt</code>
            contains the specified string.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression><eg>
'test.bin'
=> file:write-binary(xs:hexBinary('00'))
=> file:read-text(fallback := true())
=> string-to-codepoints()
          </eg></fos:expression>
          <fos:result>65533</fos:result>
          <fos:postamble>Returns the codepoint value of the Unicode replacement character.</fos:postamble>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2024-07-02">
        <p><code>$options</code> parameter added.</p>
      </fos:change>
      <fos:change issue="2016" PR="2077" date="2024-07-02">
        <p>The normalization of newlines has been made explicit.</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="read-text-lines" prefix="file">
    <fos:signatures>
      <fos:proto name="read-text-lines" return-type="xs:string*">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg name="options" type="(xs:string | map(*))?" default="()"/>
      </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>Returns the contents of a file as a sequence of strings, separated at newline
        boundaries.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the contents of a file as a sequence of strings, separated at newline
        boundaries.</p>
      <p>Any of the character sequences <char>U+000A</char>, <char>U+000D</char>, or
         <char>U+000D</char> followed by <char>U+000A</char> is interpreted as newline.</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 <xtermref spec="FO40" ref="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>"UTF-8"</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 <xtermref spec="FO40" ref="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>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="unknown-encoding"/> is raised if the specified encoding
        is invalid or not supported by the implementation.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression><eg>
let $file := 'numbers.txt'
let $data := (1 to 5) ! string()
return (
  file:write-text-lines($file, $data),
  file:read-text-lines($file) => deep-equal($data)
)
          </eg></fos:expression>
          <fos:result>true()</fos:result>
          <fos:postamble>Can be used to prove that the written and read strings are equal.</fos:postamble>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2024-07-02">
        <p><code>$fallback</code> parameter added.</p>
      </fos:change>
      <fos:change issue="2460" PR="2510" date="2026-03-11">
         <p>The <code>$fallback</code> parameter has been integrated into the options map.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="write" prefix="file">
    <fos:signatures>
      <fos:proto name="write" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="item()*" name="value"/>
        <fos:arg type="(element(output:serialization-parameters) | map(*))?" default="()" name="options"/>
      </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>Writes a serialized value to a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Serializes a value and appends the resulting string to a file.
        If the file pointed to by <code>$file</code> already exists, it will be overwritten;
        otherwise, it will be created.</p>
      <p>
        The <code>$options</code> argument controls the way how <code>$value</code> is serialized.
        The semantics are the same as for <xspecref spec="FO40" ref="func-serialize"/>.
        In contrast to <code>fn:serialize</code>, the encoding stage will not be skipped by
        this function.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:write('numbers.txt', 1 to 10)</fos:expression>
          <fos:result narrative="true">Writes 10 numbers to the file <code>numbers.txt</code>.</fos:result>
        </fos:test>
        <fos:test spec="XQuery">
          <fos:expression><eg><![CDATA[
file:write(
  'result.xml',
  <result><done/></result>,
  { 'encoding': 'us-ascii', 'indent': true() }
)
          ]]></eg></fos:expression>
          <fos:result narrative="true">Serializes an indented element node as <code>US-ASCII</code> and
            writes it to the file <code>result.xml</code>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression><eg>
file:write(
  'numbers.json',
  map:build(1 to 10, string#1),
  { 'method': 'json' }
)
          </eg></fos:expression>
          <fos:result narrative="true">Writes a map, serialized as JSON, to a specified file.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2025-07-07">
        <p><code>$options</code> can now be a map, in alignment with <code>fn:serialize</code>.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="write-binary" prefix="file">
    <fos:signatures>
      <fos:proto name="write-binary" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="xs:base64Binary" name="value"/>
        <fos:arg type="xs:integer?" default="0" name="offset"/>
      </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>Writes binary data to a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Writes the binary data of an <code>xs:base64Binary</code> item to a file.
        If the file pointed to by <code>$file</code> already exists, it will be overwritten;
        otherwise, it will be created.</p>
      <p>If <code>$offset</code> is specified and not an empty sequence, data will be written 
        starting at this file position, and existing bytes will be overwritten.
        The operation may resize the existing file.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
      <note>
        <p>Supplying an offset makes sense only if the file already exists.</p>
      </note>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="out-of-range"/> is raised if the specified offset is negative,
        or if it exceeds the current file size.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:write-binary('data.bin', xs:hexBinary('414243'))</fos:expression>
          <fos:result narrative="true">Writes the bytes <code>0x44</code>, <code>0x43</code> and <code>0x41</code>
            to the file <code>data.bin</code>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:write-binary('data.bin', xs:hexBinary('44', 2))</fos:expression>
          <fos:result narrative="true">If this expression is called after the previous one, overwrites the last
            byte with <code>0x44</code>.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="write-text" prefix="file">
    <fos:signatures>
      <fos:proto name="write-text" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="xs:string" name="value"/>
        <fos:arg type="xs:string?" default="'UTF-8'" name="encoding"/>
      </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>Writes a string to a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Writes a string to a file.
        If the file pointed to by <code>$file</code> already exists, it will be overwritten.</p>
      <p>If no encoding is supplied, <code>UTF-8</code> is used as output encoding.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="unknown-encoding"/> is raised if the specified encoding
        is invalid or not supported by the implementation.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:write-text('todos.txt', 'get organized')</fos:expression>
          <fos:result narrative="true">Writes a string to the file <code>todos.txt</code>.
            The file is created if it does not already exist.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="write-text-lines" prefix="file">
    <fos:signatures>
      <fos:proto name="write-text-lines" return-type="empty-sequence()">
        <fos:arg type="xs:string" name="file"/>
        <fos:arg type="xs:string*" name="values"/>
        <fos:arg type="xs:string?" default="'UTF-8'" name="encoding"/>
      </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>Writes strings to a file.</p>
    </fos:summary>
    <fos:rules>
      <p>Writes strings to a file, each followed by the operating-system specific newline character.
        If the file pointed to by <code>$file</code> already exists, it will be overwritten;
        otherwise, it will be created.</p>
      <p>If no encoding is supplied, <code>UTF-8</code> is used as output encoding.</p>
      <p>The function returns the empty sequence if the operation is successful.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the parent directory of
        the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="is-dir"/> is raised if the specified path points to a
        directory.</p>
      <p>
        <errorref spec="FILE40" code="unknown-encoding"/> is raised if the specified encoding
        is invalid or not supported by the implementation.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:write-text-lines('numbers.txt', (1 to 5) ! string())</fos:expression>
          <fos:result narrative="true">Writes the string representation of the integers 1 to 5 to the file
            <code>numbers.txt</code>.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="name" prefix="file">
    <fos:signatures>
      <fos:proto name="name" return-type="xs:string">
        <fos:arg type="xs:string" name="path"/>
      </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 a file or directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the name of a file or directory.
        An empty string is returned if the path points to the root directory.</p>
      <p>This function is <xtermref spec="FO40" ref="dt-deterministic">deterministic</xtermref>:
        the path is neither checked for correctness nor looked up in the file system.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:name('')</fos:expression>
          <fos:result>''</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:name('/')</fos:expression>
          <fos:result>''</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:name('hello.txt')</fos:expression>
          <fos:result>'hello.txt'</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:name('dir/')</fos:expression>
          <fos:result>'dir'</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:name('dir/file.txt')</fos:expression>
          <fos:result>'file.txt'</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:name('dir/..')</fos:expression>
          <fos:result>'..'</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>file:name('file:///tmp/001.bin')</fos:expression>
          <fos:result>'001.bin'</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="parent" prefix="file">
    <fos:signatures>
      <fos:proto name="parent" return-type="xs:string?">
        <fos:arg type="xs:string" name="path"/>
      </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>Returns the path to the parent directory of a given path.</p>
    </fos:summary>
    <fos:rules>
      <p>Transforms the given path into an absolute path, as specified by
        <loc href="#fn.resolve-path">file:resolve-path</loc>, and returns the parent
        directory.</p>
      <p>An empty sequence is returned if the path points to a root directory.</p>
      <note>
        <p>The inverse function is <loc href="#func-file-children">file:children</loc>.</p>
      </note>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:parent('/')</fos:expression>
          <fos:result>()</fos:result>
        </fos:test>
      </fos:example>
      <fos:example>
        <fos:test>
          <fos:expression>file:current-dir() = file:parent('abc')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="children" prefix="file">
    <fos:signatures>
      <fos:proto name="children" return-type="xs:string*">
        <fos:arg type="xs:string" name="path"/>
      </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>Returns the paths of all files and directories that are located in the given
        directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the paths of all files and directories that are located in the given
        directory. The order of the items in the resulting sequence is not defined.
        The references to the specified directory and its parent directory
        (<code>.</code> and <code>..</code>) are not returned.</p>
      <note>
        <p>The inverse function is <loc href="#func-file-parent">file:parent</loc>; a related function
        is <loc href="#func-file-list">file:list</loc>.</p>
      </note>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the specified path
        does not point to an existing directory.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression><eg>count(file:children('.'))</eg></fos:expression>
          <fos:result narrative="true">Counts the files and directories in the <termref def="current-working-dir"/>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>
            <eg>file:children('path/to/media/')
      [matches(., '\.(avi|mpg|mp4)$', 'i')]</eg>
          </fos:expression>
          <fos:result narrative="true">Returns the paths to large videos found in a specific directory.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="descendants" prefix="file">
    <fos:signatures>
      <fos:proto name="descendants" return-type="xs:string*">
        <fos:arg type="xs:string" name="path"/>
      </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>Returns the paths of all files and directories that are located in the given
        directory and its subdirectories.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the paths of all files and directories that are located in the given
        directory and its subdirectories. The order of the items in the resulting sequence
        is not defined.
        The references to the specified directory and its parent directory
        (<code>.</code> and <code>..</code>) are not returned.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="no-dir"/> is raised if the specified path
        does not point to an existing directory.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if any other error occurs.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>count(file:descendants('.')[file:is-directory(.)])</fos:expression>
          <fos:result narrative="true">Counts the subdirectories in the <termref def="current-working-dir"/>.</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression><eg>
for $file in file:descendants('.')
where file:last-modified($file) > current-dateTime() - xs:dayTimeDuration('PT1H')
return $file
          </eg></fos:expression>
          <fos:result narrative="true">Returns the paths to all files that have been modified in the last hour.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2024-07-02"><p>New in 4.0.</p></fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="path-to-native" prefix="file">
    <fos:signatures>
      <fos:proto name="path-to-native" return-type="xs:string">
        <fos:arg type="xs:string" name="path"/>
      </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>Transforms a path to a canonical representation.</p>
    </fos:summary>
    <fos:rules>
      <p>Transforms a URI, an absolute path, or relative path to a canonical, operating-system specific
        path representation. A canonical path is both absolute and unique and thus contains
        no redirections such as references to parent directories or symbolic links.</p>
      <p>If the resulting path points to a directory, it will be suffixed with the
       operating-system specific directory separator.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="not-found"/> is raised if the specified path does not exist.</p>
      <p>
        <errorref spec="FILE40" code="io-error"/> is raised if an error occurs while trying
        to generate the native path.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:path-to-native('/')</fos:expression>
          <fos:result narrative="true">Returns <code>/</code> on a UNIX-based system.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="path-to-uri" prefix="file">
    <fos:signatures>
      <fos:proto name="path-to-uri" return-type="xs:anyURI">
        <fos:arg type="xs:string" name="path"/>
      </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>Transforms a file system path into a URI.</p>
    </fos:summary>
    <fos:rules>
      <p>Transforms a file system path into a URI with the <code>file</code> scheme. If the
        path is relative, it is first resolved against the <termref def="current-working-dir"/>.</p>
      <p>This function is <xtermref spec="FO40" ref="dt-deterministic">deterministic</xtermref>:
        the path is neither checked for correctness nor looked up in the file system.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:path-to-uri('/temp')</fos:expression>
          <fos:result narrative="true">Returns <code>file:///temp</code> on a UNIX-based system</fos:result>
        </fos:test>
        <fos:test>
          <fos:expression>contains(file:path-to-uri('a b'), '%20')</fos:expression>
          <fos:result>true()</fos:result>
          <fos:postamble>Space characters will be encoded to <code>%20</code>.</fos:postamble>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="resolve-path" prefix="file">
    <fos:signatures>
      <fos:proto name="resolve-path" return-type="xs:string">
        <fos:arg type="xs:string" name="path"/>
        <fos:arg type="xs:string?" name="base" default="()"/>
      </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>Transforms a relative path into an absolute operating system path.</p>
    </fos:summary>
    <fos:rules>
      <p>Transforms a relative path into an absolute operating system path.
        The following rules apply in order:</p>
      <olist>
        <item>
          <p>If <code>$path</code> is an absolute path, it is not changed.</p>
        </item>
        <item>
          <p>Otherwise, if <code>$base</code> is the empty sequence, <code>$path</code> is
            resolved against the <termref def="current-working-dir"/>.</p>
        </item>
        <item>
          <p>Otherwise, it is resolved against the supplied base path or, if the base path does
            not point to a directory, to its parent directory.
            An error is raised if the base is a relative path.</p>
        </item>
      </olist>
      <p>If the resulting path points to a directory, it will be suffixed with the
        operating-system specific directory separator.</p>
    </fos:rules>
    <fos:errors>
      <p>
        <errorref spec="FILE40" code="is-relative"/> is raised if the specified base directory
          is relative.</p>
    </fos:errors>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:resolve-path('INF', 'C:/Windows/')</fos:expression>
          <fos:result>'C:/Windows/INF/'</fos:result>
          <fos:postamble>The result refers to a Windows system.</fos:postamble>
        </fos:test>
        <fos:test>
          <fos:expression>file:resolve-path('data.bin', 'C:/Temp')</fos:expression>
          <fos:result>'C:/data.bin'</fos:result>
          <fos:postamble>The result refers to a Windows system.</fos:postamble>
        </fos:test>
        <fos:test>
          <fos:expression>file:resolve-path('hilda/notes.txt', '/home/')</fos:expression>
          <fos:result>'/home/hilda/notes.txt'</fos:result>
          <fos:postamble>The result refers to a UNIX-based system.</fos:postamble>
        </fos:test>
      </fos:example>
    </fos:examples>
    <fos:changes>
      <fos:change issue="2016" PR="2077" date="2024-07-02">
        <p><code>$base</code> parameter added.</p>
      </fos:change>
    </fos:changes>
  </fos:function>

  <fos:function name="dir-separator" prefix="file">
    <fos:signatures>
      <fos:proto name="dir-separator" return-type="xs:string"/>
    </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>Returns the directory separator.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the value of the operating-system specific directory separator, which usually
        is <code>/</code> on UNIX-based systems and <code>\</code> on Windows systems.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:dir-separator() = ('/', '\')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="line-separator" prefix="file">
    <fos:signatures>
      <fos:proto name="line-separator" return-type="xs:string"/>
    </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>Returns the line separator.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the value of the operating-system specific line separator, which usually is
        <code>&amp;#10;</code> on UNIX-based systems, <code>&amp;#13;&amp;#10;</code> on
        Windows systems and <code>&amp;#13;</code> on old Mac systems.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>matches(file:line-separator(), '^(\n|\r\n|\r)$')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="path-separator" prefix="file">
    <fos:signatures>
      <fos:proto name="path-separator" return-type="xs:string"/>
    </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>Returns the path separator.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the value of the operating-system specific path separator, which usually is
        <code>:</code> on UNIX-based systems and <code>;</code> on Windows systems.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:dir-separator() = (':', ';')</fos:expression>
          <fos:result>true()</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="temp-dir" prefix="file">
    <fos:signatures>
      <fos:proto name="temp-dir" return-type="xs:string"/>
    </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>Returns the path to the temporary-file directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the path to the default temporary-file directory of an operating system.</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression>file:write-text(file:temp-dir() || 'todos.txt', 'get on going')</fos:expression>
          <fos:result narrative="true">Write a text string to a file in the temporary-file directory.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="base-dir" prefix="file">
    <fos:signatures>
      <fos:proto name="base-dir" return-type="xs:string?"/>
    </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>Returns the base directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the <termref def="base-dir"/>.
        If defined, the function returns the same result as the expression
        <code>file:parent(static-base-uri())</code>. Otherwise, it returns an empty sequence</p>
    </fos:rules>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression><eg>
let $dir := file:base-dir() otherwise file:create-temp-dir()
return file:write-text($dir || 'todos.txt', 'get up')
          </eg></fos:expression>
          <fos:result narrative="true">Writes <code>todos.txt</code> to the <termref def="base-dir"/> or,
if it is not defined, to a temporary directory.</fos:result>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>

  <fos:function name="current-dir" prefix="file">
    <fos:signatures>
      <fos:proto name="current-dir" return-type="xs:string"/>
    </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>Returns the current working directory.</p>
    </fos:summary>
    <fos:rules>
      <p>Returns the <termref def="current-working-dir"/>.
      All relative file paths are resolved against this directory.       
      </p>
    </fos:rules>
    <fos:equivalent style="xpath-expression" covers-error-cases="true">
      file:resolve-path('.')</fos:equivalent>
    <fos:examples>
      <fos:example>
        <fos:test>
          <fos:expression><eg>
file:path-to-native('todos.txt') =
file:path-to-native(file:current-dir() || 'todos.txt')
          </eg></fos:expression>
          <fos:result>true()</fos:result>
          <fos:postamble>Both paths refer to the same file.</fos:postamble>
        </fos:test>
      </fos:example>
    </fos:examples>
  </fos:function>
</fos:functions>
